// This is a -*- C++ -*- file.
// MK sagt: Das hier ist aus so einem STL-Buch und ein bissel
// angepa"st. "
//
// string                    einfache String-Klasse,
// die hier hinzugefgt wurde, um eine String-Klasse entsprechend
// dem Verhalten der Klasse string des Standards zu haben.
// Definition siehe typedef am Ende dieser Datei.

#ifndef stringtemplate
#define stringtemplate

#include<stddef.h>                     // size_t
#include<iostream.h>                   // ostream
#include<bool>
#include<assert>
#include<cstring>

template<class T>
class basic_string
{
public:
  basic_string();                       // Standardkonstruktor
  basic_string(const T *);              // allg. Konstruktor
  basic_string(const basic_string&);    // Kopierkonstruktor
  ~basic_string();                      // Destruktor
  void assign(const basic_string&);      // Zuweisung eines basic_strings
  void assign(T *);                // Zuweisung eines T*
  const T& at(size_t position) const; // Zeichen holen
  T& at(size_t position);          // Zeichen holen,
  //  Referenz erlaubt ndern
  int length() const { return len;}
  friend void anzeigen(ostream&, const basic_string<T>&);


  // MK sagt: Das hier ist von mir:
  typedef int size_type;
  const size_type npos=-1;
  const T *c_str() const {return start;}
  size_type find(char c) const {
    const char *t = strchr(start, c);
    return t ? t-start : npos;
  }
  basic_string &operator+=(char c) {
    char s[2];
    s[0] = c;
    s[1] = 0;
    return *this+=s;
  }

  size_type roundedup(size_type s) {
    return (s + 15) &~15;
  }

  basic_string &remove(size_type index, size_type count) {
    int i;
    for (i=index+count; i<=len; i++) {
      start[i-count] = start[i];
    }
    if (len > count) len -= count;
    else len=0;
    start[len] = 0;
    return *this;
  }
  basic_string &replace(size_type index, size_type count, size_type
			ccount, T c)
  {
    remove(index, count);
    insert(index, ccount, c);
    return *this;
  }
  basic_string &insert(size_type index, size_type count, T c)
  {
    T *newcontent = new T[(room = roundedup(len+count+1))];
    len += count;
    T *Q = newcontent;
    T *P = start;
    while (index != 0) *Q++ = *P++, index--;
    while (count != 0) *Q++ = c, count--;
    while (*P) *Q++ = *P++;
    *Q = 0;
    delete[] start;
    start = newcontent;
    return *this;
  }
  basic_string substr(size_type index, size_type count) 
  {
    basic_string<T> temp(start + index);
    temp[count] = 0;
    temp.len = count;
    return temp;
  }

  // MK sagt: ab hier nimmer.
  basic_string& operator=(const basic_string<T>&); // Zuweisung eines basic_strings
  basic_string& operator=(const T*);   // Zuweisung eines T*
  const T& operator[](int) const;  // Index-Operator
  T& operator[](int);              // Index-Operator
  basic_string& operator+=(const basic_string&); // Anhngen eines basic_strings
  basic_string& operator+=(const T*); // Anhngen eines T*

  inline bool operator<(const basic_string& m) const;
  inline bool operator>(const basic_string& m) const;
  inline bool operator==(const basic_string& m) const;
  inline bool operator!=(const basic_string& m) const;
  inline bool operator<=(const basic_string& m) const;
  inline bool operator>=(const basic_string& m) const;

  bool operator<(const T* m) const;
  bool operator==(const T* m) const;

  inline bool operator>(const T* m) const;
  inline bool operator!=(const T* m) const;
  inline bool operator<=(const T* m) const;
  inline bool operator>=(const T* m) const;

  // Iteratoren
  T* begin() const { return start;}
  T* end() const { return start+len;}
  // Ausgabeoperator
  friend ostream& operator<<(ostream&, const basic_string<T>&);

private:
  T *start;                        // Zeiger auf den Anfang
  size_t len;                      // Lnge
  size_t room;                     // reservierter Platz
};

// Hilfsfunktion: String kopieren
template<class T>
static void copy(T *ziel, const T *quelle)
{   while(*quelle != T(0)) *ziel++ = *quelle++;
    *ziel = T(0);
}

// Hilfsfunktion: Lnge eines C-Strings ermitteln
template<class T>
static size_t laenge(const T *s)
{   size_t sl = 0;
    while(*s++) sl++;
    return sl;
}

template<class T>
basic_string<T>::basic_string()          // Standardkonstruktor
  : len(0), room(roundedup(1))
{   start = new T[room];                     // Platz fr 0
    *start = T(0);                        // leerer String
}

template<class T>
basic_string<T>::basic_string(const T *s)              // allg. Konstruktor
{   len = laenge(s);
    start = new T[(room = roundedup(len+1))];
    copy(start, s);
}

template<class T>
basic_string<T>::basic_string(const basic_string<T> &m)           // Kopierkonstruktor
{   start = new T[(room = roundedup(m.len+1))];
    len   = m.len;
    copy(start, m.start);
}

template<class T>
basic_string<T>::~basic_string()                          // Destruktor
{   delete [] start;
}

template<class T>
void basic_string<T>::assign(const basic_string<T> &m)  // Zuweisung eines basic_strings
{   if (this != &m)                     // nicht auf sich selbst zuweisen
    {  delete [] start;                 // alten Platz freigeben
       start = new T[room=roundedup(m.len+1)];       // neuen Platz beschaffen
       len   = m.len;
       copy(start, m.start);
    }
}

template<class T>
void basic_string<T>::assign(T *s)             // Zuweisung eines T*
{   delete [] start;                      // alten Platz freigeben
    len = laenge(s);
    start = new T[room=roundedup(len+1)];
    copy(start, s);
}

template<class T>
const T& basic_string<T>::at(size_t position) const  // Zeichen holen
{   assert(position < len);  // Nullbyte lesen ist nicht erlaubt
    return start[position];
}

template<class T>
T& basic_string<T>::at(size_t position) // Zeichen per Referenz holen
{   assert(position < len);  // Nullbyte lesen ist nicht erlaubt
    return start[position];
}

template<class T>
void anzeigen(ostream &os, const basic_string<T> &m)
{  os << m.start;
}


template<class T>
basic_string<T>& basic_string<T>::operator=(const basic_string<T>& m) // Zuweisung eines basic_strings
{   if (this != &m)                     // nicht auf sich selbst zuweisen
    {  delete [] start;                 // alten Platz freigeben
       start = new T[room=roundedup(m.len+1)];       // neuen Platz beschaffen
       len   = m.len;
       copy(start, m.start);
    }
    return *this;
}

template<class T>
basic_string<T>& basic_string<T>::operator=(const T* s)      // Zuweisung eines T*
{   delete [] start;                      // alten Platz freigeben
    len = laenge(s);
    start = new T[room=roundedup(len+1)];
    copy(start, s);
    return *this;
}

// Index-Operator zum lesen
template<class T>
const T& basic_string<T>::operator[](int pos) const
{   assert(pos >= 0 && pos<= len);  // Nullbyte lesen ist erlaubt!
    return start[pos];
}

// Index-Operator fr ndernden Zugriff
template<class T>
T& basic_string<T>::operator[](int pos)
{   assert(pos >= 0 && pos<= len);  // potentiell gefhrlich (s. readme)
    return start[pos];
}

// Operator +=
template<class T>
basic_string<T>& basic_string<T>::operator+=(const basic_string<T>& m)
{   
  return *this+=m.start;
}

template<class T>
basic_string<T>& basic_string<T>::operator+=(const T* s)
{ 
  int slen = laenge(s);
  if (len + slen + 1 <= room) {
    copy(start + len, s);
    len += slen;
  }
  else {
    T *temp = new T[len + slen +1];
    copy(temp, start);
    copy(temp+len, s);
    len += slen;
    delete [] start;
    start = temp;
  }
  return *this;
}

template<class T>
bool basic_string<T>::operator<(const char *m) const
{   const T *s1 = start, *s2 = m;
    while (*s1 && *s2)
       if (*s1 != *s2) return (*s1 < *s2);
       else { s1++; s2++;}
    return (!*s1 && *s2);  // s1 ist krzer
}

template<class T>
bool basic_string<T>::operator>(const char *m) const
{   const T *s1 = start, *s2 = m;
    while(*s1 && *s2)
       if (*s1 != *s2) return (*s1 > *s2);
       else { s1++; s2++;}
    return (*s1 && !*s2);  // s1 ist krzer
}

template<class T>
bool basic_string<T>::operator==(const char *m) const
{    
  const T *s1 = start, *s2 = m;
  while (*s1 && *s2) {
    if (*s1++ != *s2++) return false;
  }
  return *s1==*s2;
}

template<class T>
inline bool basic_string<T>::operator!=(const char * m) const
{    return !operator==(m);
}

template<class T>
inline bool basic_string<T>::operator<=(const char * m) const
{    
  return !(*this > m);
}

template<class T>
inline bool basic_string<T>::operator>=(const char * m) const
{    return !(*this < m);
}

template<class T>
inline bool basic_string<T>::operator<(const basic_string<T>& m) const
{   
  return *this < m.start;
}

template<class T>
inline bool basic_string<T>::operator==(const basic_string<T>& m) const
{  
  return *this == m.start;
}

template<class T>
inline bool basic_string<T>::operator!=(const basic_string<T>& m) const
{ 
  return !(*this == m);
}

template<class T>
inline bool basic_string<T>::operator>(const basic_string<T>& m) const
{    
  return m < *this;
}

template<class T>
inline bool basic_string<T>::operator<=(const basic_string<T>& m) const
{    return !(*this > m);
}

template<class T>
inline bool basic_string<T>::operator>=(const basic_string<T>& m) const
{    return !(*this < m);
}

// Ein- und Ausgabeoperatoren (keine Elementfunktionen)
template<class T>
istream& operator>>(istream &is, basic_string<T> &m)
{
    const int maxl = 1024; // angenommene max Zeilenlnge
    T buf[maxl];
    is >> buf;   //  keine Prfung auf maxl !!!!
    m = buf;               // Aufruf von operator=(T*)
    return is;
}


template<class T>
inline ostream& operator<<(ostream &os, const basic_string<T> &m)
{   os << m.start;
    return os;
}

// globaler Operator +
template<class T>
basic_string<T> operator+(const basic_string<T>& a, const basic_string<T>& b)
{   basic_string<T> temp = a;
    return temp += b;
}

template<class T>
basic_string<T> operator+(const basic_string<T>& a, const T* b)
{   basic_string<T> temp = a;
    return temp += b;
}

template<class T>
basic_string<T> operator+(const T* a, const basic_string<T>& b)
{   basic_string<T> temp = a;
    return temp += b;
}

template<class T>
basic_string<T> operator+(const basic_string<T>& a, T b)
{   basic_string<T> temp = a;
    return temp += b;
}

typedef basic_string<char> string;
#endif // stringtemplate
