#ifndef __STRINGS_H
#define __STRINGS_H

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef __ARRAY_H
#include <array.h>
#endif

#ifndef __REGEXP_H
#include <regexp.h>
#endif
      
      
// @doc EXTERNAL

// @class Classe per la definizione della stringhe
//
// @base public | TObject
class TString : public TObject
// @author:(INTERNAL) Guido
{
  // @access Protected Member
protected:  
  // @cmember Puntatore alla stringa
  char* _str;   
  // @cmember Lunghezza della stringa
  int _size;    

  // @cmember Espande la stringa per altri caratteri
  int make_room(int size);
  // @cmember Inizializza con la stringa puntata da char* di lunghezza size
  TString& set(const char*); 

  // @cmember Costruttore per consentire la derivazione delle TFixed_string
  TString(char* str, int size) : _str(str), _size(size) 
  {}

  // @access Public member
public:
  // @cmember Cambia la dimensione della stringa eventualmente preservandone il contenuto iniziale
  virtual void resize(int size, bool cpy);

  // @cmember Costruttore
  TString();
  // @cmember Costruttore di default per una stringa data
  TString(int size, char c='\0');
  // @cmember Costruttore a partire da una stringa s
  TString(const char* s);
  // @cmember Costruttore da un oggetto TString s
  TString(const TString& s);
  // @cmember Distruttore
  virtual ~TString();

  // @cmember Ritorna il nome della classe
  virtual const char* class_name() const;
  // @cmember Ritorna l'identificatore della classe
  virtual word class_id() const;
  // @cmember Controlla se si tratta di una stringa valida (diversa da NULL)
  virtual bool ok() const
  { return _str != NULL; }
  // @cmember Duplica una stringa
  virtual TObject* dup() const;
  // @cmember Stampa una stringa
  virtual void print_on(ostream& out) const;
  // @cmember Legge una stringa
  virtual void read_from(istream& in);
  // @cmember Ritorna il valore hash della stringa
  virtual word hash() const;

  // @cmember const char * | operator const char*() | | Trasforna una stringa 
  //          in puntatore a carattere 
  operator const char*() const
  { return (const char*)_str; }
  // @cmember Ritorna un riferimento al carattere i-esimo della stringa
  char& operator[](int i)
  { 
    CHECKD(i >= 0 && i <= _size, "Bad string subscript: ", i);
    return _str[i]; 
  }
  // @cmember Ritorna il carattere i-esimo della stringa
  char operator[](int i) const
  { 
    CHECKD(i >= 0 && i <= _size, "Bad string subscript: ", i);
    return _str[i]; 
  }  

  // @cmember Ritorna la dimensione allocata della stringa
  int size() const
  { return _size; }
  // @cmember Ritorna la lunghezza della stringa (numero di caratteri)
  int len() const 
  { return strlen(_str); }
  // @cmember Controlla se la stringa e' vuota (TRUE se non contiene caratteri)
  bool empty() const
  { return *_str == '\0'; }
  // @cmember Controlla se la stringa non e' vuota (TRUE se contiene caratteri)
  bool not_empty() const
  { return *_str != '\0'; }
  // @cmember Controlla se la stringa e' vuota o contiene solo whitespace (TRUE se vuota)
  bool blank() const;

  // @cmember Ritorna la posizione del carattere char nell'oggetto TString
  int find(char, int from = 0) const;
  // @cmember Ritorna la posizione della stringa s nell'oggetto TString
  int find(const char* s, int from = 0) const;
  // @cmember Sostituisce le occorrenze di <p find_char> col carattere <p replace_char>
  int replace(char find_char, char replace_char);

  // @cmember Ritorna l'oggetto TString composto dai count caratteri da sinistra
  const TString& left(int count) const;
  // @cmember Ritorna l'oggetto TString composto dai count caratteri a partire da from
  const TString& mid(int from, int count = -1) const;
  // @cmember Ritorna la stringa da from a to (escluso)
  const TString& sub(int from, int to = -1) const;
  // @cmember Ritorna l'oggetto TString composto dai count caratteri da destra
  const TString& right(int count) const;

  // @cmember Ritorna un oggetto TString temporaneo composto dai count caratteri da sinistra
  TString sleft(int count) const 
  { return ((TString)left(count)); }
  // @cmember Ritorna un oggetto TString temporaneo composto dai count caratteri a partire da from
  TString smid(int from, int count = -1) const 
  { return ((TString)mid(from, count)); }
  // @cmember Ritorna un oggetto TString temporaneo composto dai caratteri da from a to (escluso)
  TString ssub(int from, int to = -1) const 
  { return ((TString)sub(from, to)); }
  // @cmember Ritorna un oggetto TString temporaneo composto dai count caratteri da destra
  TString sright(int count) const 
  { return ((TString)right(count)); }

  // @cmember Riempe la stringa con n caratteri c
  TString& fill(char c, int n = -1);
  // @cmember Riempe la stringa con n caratteri spazio (chiama <mf TString::resize>)
  TString& spaces(int n = -1)
  { return fill(' ', n); }
  // @cmember Sovrascrive la stringa s dalla posizione pos
  TString& overwrite(const char* s, int pos = 0);
  // @cmember Inserisce la stringa s dalla posizione pos
  TString& insert(const char* s, int pos = 0);

  // @cmember Elimina tutti i caratteri contenuti in k
  TString& strip(const char* k);
  // @cmember Elimina tutti gli spazi non contenuti tra apici singoli o doppi
  TString& strip_spaces();
  // @cmember Elimina tutti gli spazi doppi
  TString& strip_d_spaces();
  // @cmember Elimina gli spazi da sinistra o i primi n caratteri (da sinistra).
  TString& ltrim(int n = 0);
  // @cmember Elimina gli spazi da destra o i primi n caratteri (da destra).
  TString& rtrim(int n = 0);
  // @cmember Composizione di <mf TString::ltrim> e <mf TString::rtrim> per eliminare
  //          gli spazi iniziali e finali
  TString& trim();
  // @cmember Aggiunge spazi a destra fino alla dimensione indicata
  TString& rpad(const int n,const char c=' ');
  // @cmember Aggiunge spazi a destra fino alla dimensione indicata
  TString& lpad(const int n,const char c=' ');

  // @cmember Giustifica l'oggetto stringa a destra
  TString& right_just(int n = -1, char c = ' ');
  // @cmember Centra l'oggetto stringa
  TString& center_just(int n = -1, char c = ' ');
  // @cmember Giustifica l'oggetto stringa a sinistra
  TString& left_just(int n = -1, char c = ' ');

  // @cmember Formatta una stringa usando il formato dato da pic
  TString& picture(const char* pic, const char* s);
   
  // @cmember Manda un output formattato alla stringa oggetto
  virtual TString& format(const char* fmt, ...);

  // @cmember Tronca la stringa alla posizione n-esima.
  TString& cut(int n);
  
  // @cmember Ritorna il buffer interno della stringa (usare con attenzione!)
  char* get_buffer(int min_size = -1);

  // @cmember Converte la stringa in maiuscolo
  TString& upper();
  // @cmember Converte la stringa in minuscolo
  TString& lower();
  // @cmember Permette di ttrovare il plurale di una stringa
  TString& add_plural(long num, const char * name);

  // @cmember Assegna la stringa passata con indirizzo
  const TString& operator =(const TString& s)
  { return set(s._str); }
  // @cmember Assegna la stringa passata
  const TString& operator =(const char* s)
  { return set(s); }

  // @cmember Concatena una stringa all'oggetto stringa
  TString& operator <<(const char*);
  // @cmember Concatena un carattere all'oggetto stringa
  TString& operator <<(char);
  // @cmember Concatena un intero all'oggetto stringa
  TString& operator <<(int);
  // @cmember Concatena un long all'oggetto stringa
  TString& operator <<(long);
  // @cmember Concatena un double all'oggetto stringa
  TString& operator <<(double);
  // @cmember Concatena un oggetto all'oggetto stringa
  TString& operator <<(const TObject& obj);
  // @cmember Concatena una stringa all'oggetto stringa (usato per aumentare l'efficienza)
  TString& operator <<(const TString& str);


  // @cmember Controlla se due stringhe sono uguali
  bool operator ==(const char* s) const
  { return  s ? strcmp(_str, s) == 0 : empty();}
  // @cmember Controlla se due stringhe sono uguali
  bool operator ==(char* s) const
  { return s ? strcmp(_str, s) == 0 : empty();}
  // @cmember Controlla se due stringe sono uguali
  bool operator ==(const TString& s) const
  { return strcmp(_str, s._str) == 0; }
  // @cmember Controlla se due stringhe sono diverse
  bool operator !=(const char* s) const
  { return s ? strcmp(_str, s) != 0 : not_empty();}
  // @cmember Controlla se due stringhe sono diverse
  bool operator !=(char* s) const
  { return s ? strcmp(_str, s) != 0 : not_empty();}
  // @cmember Controlla se due stringhe sono diverse
  bool operator !=(const TString& s) const
  { return strcmp(_str, s._str) != 0; }
  // @cmember Controlla se una stringa e' minore di un'altra
  bool operator  <(const char* s) const
  { return s ? strcmp(_str, s)  < 0 : FALSE;}
  // @cmember Controlla se una stringa e' maggiore di un'altra
  bool operator  >(const char* s) const
  { return s ? strcmp(_str, s)  > 0  : not_empty();}
  // @cmember Controlla se una stringa e' maggiore o uguale ad un'altra
  bool operator >=(const char* s) const
  { return s ? strcmp(_str, s) >= 0 : TRUE;}
  // @cmember Controlla se una stringa e' minore o uguale ad un'altra
  bool operator <=(const char* s) const
  { return s ? strcmp(_str, s) <= 0 : empty();}
  // @cmember Controlla se una stringa e' minore di un'altra
  bool operator  <(const TString & s) const
  { return strcmp(_str, s._str)  < 0; }
  // @cmember Controlla se una stringa e' maggiore di un'altra
  bool operator  >(const TString & s) const
  { return strcmp(_str, s._str)  > 0; }
  // @cmember Controlla se una stringa e' maggiore o uguale ad un'altra
  bool operator >=(const TString & s) const
  { return strcmp(_str, s._str) >= 0; }
  // @cmember Controlla se una stringa e' minore o uguale ad un'altra
  bool operator <=(const TString & s) const
  { return strcmp(_str, s._str) <= 0; }
  // @cmember Confronta usando le regular expression
  bool match(const char* pat) const
  { return ::match(pat, _str); }
  // @cmember Compara due stringhe (o i primi max caratteri)
  int compare(const char* s, int max = -1, bool ignorecase = FALSE) const;
};

// @doc EXTERNAL

// @class TFixed_string | Classe per la definizione di stringhe di lunghezza
//                        fissa e non rilocabili dinamicamente
//
// @base public | TString
class TFixed_string : public TString
// @author:(INTERNAL) Guido
{

  // @access Protected Member
protected:
  // @cmember Causa un erroe fatale
  virtual void resize(int size, bool cpy);

  // @access Public Member
public:
  // @cmember Costruttore
  TFixed_string(const char* str, int size = -1);
  // @cmember Distruttore
  virtual ~TFixed_string();

#ifndef __WATCOMC__
  virtual
#endif
    // @cmember Manda un output formattato alla stringa oggetto
    TString& format(const char* fmt, ...);

  // @cmember Assegna la stringa passata con indirizzo
  const TString& operator =(const TString& s)
  { return set((const char*)s); }
  // @cmember Assegna la stringa passata
  const TString& operator =(const char* str)
  { return set(str); }
  // @cmember Copia n caratteri nella stringa oggetto
  void strncpy(const char* s, int n);
};

// @doc EXTERNAL

// @class TString16 | Definisce le stringhe di 16 caratteri
//
// @base public | TFixed_string
class TString16 : public TFixed_string
// @author:(INTERNAL) Guido
{
  // @access:(INTERNAL) Private member

  // @cmember:(INTERNAL) Stringa di 16 caratteri
  char _str16[17];

  // @access Public Member
public:
  // @cmember Costruttore
  TString16(const char* s = "") : TFixed_string(_str16, 17)
  { set(s); }
  // @cmember Costruttore
  TString16(const TString& s) : TFixed_string(_str16, 17)
  { set(s); }
  // @cmember Assegna una stringa
  const TString& operator =(const TString& s)
  { return set((const char*)s); }
  // @cmember Assegna una stringa
  const TString& operator =(const char* s)
  { return set(s); }

  // @comm Sono definite anche le classi <c TString80> e <c TString256> per le
  //       stringhe rispettivamente di 80 e 256 caratteri. I class member sono
  //       gli stessi, la differenza e' solo nel numero di caratteri della stringa.
};

// @doc EXTERNAL

// @class TString80 | Definisce le stringhe di 80 caratteri
//
// @base public | TFixed_string
//
// @author:(INTERNAL) Guido
//
// @comm Questa classe e' identica alla <c TString16> per quanto riguarda i public member e quindi
//       si rimanda a tale classe per ulteriori spiegazioni.
class TString80 : public TFixed_string
{
  char _str80[81];

public:
  TString80(const char* s = "") : TFixed_string(_str80, 81) { set(s); }
  TString80(const TString& s) : TFixed_string(_str80, 81) { set(s); }
  const TString& operator =(const char* s) { return set(s); }
  const TString& operator =(const TString& s) { return set((const char*)s); }
};

// @doc EXTERNAL

// @class TString256 | Definisce le stringhe di 256 caratteri
//
// @base public | TFixed_string
//
// @author:(INTERNAL) Guido
//
// @comm Questa classe e' identica alla <c TString16> per quanto riguarda i public member e quindi
//       si rimanda a tale classe per ulteriori spiegazioni.
class TString256 : public TFixed_string
{
  char _str256[257];

public:
  TString256(const char* s = "") : TFixed_string(_str256, 257) { set(s); }
  TString256(const TString& s) : TFixed_string(_str256, 257) { set(s); }
  const TString& operator =(const char* s) { return set(s); }
  const TString& operator =(const TString& s) { return set((const char*)s); }
};

// @doc EXTERNAL

// @class TFilename | Classe per la gestione dei nome dei file
//
// @base public | TString80
class TFilename : public TString80
// @author:(INTERNAL) Guido

{

  // @comm Nel caso di utilizzo di Windows 95 occorre cambiare le classe base in <c TString256>

  // @access Public Member
public:
  // @cmember Costruttore
  TFilename(const char* n = "") : TString80(n)
  {}
  // @cmember Costruttore
  TFilename(const TString& n) : TString80((const char*)n)
  {}
  // @cmember Costruttore
  TFilename(const TFilename& n) : TString80((const char*)n)
  {}

  // @cmember Assegnazione tra TFile e stringa
  const TString& operator =(const char* s)
  { return set(s); }
  // @cmember Assegnazione tra TFile ed indirizzo della stringa
  const TString& operator =(const TString& s)
  { return set((const char*)s); }
  
  // @cmember Controlla il formato del nome del file
  virtual bool ok() const;

  // @cmember Ritorna l'estensione del file
  const char* ext() const;
  // @cmember Imposta come estensione la stringa puntata da char*
  void ext(const char*);
  
  // @cmember Concatena un nome di file ad una directory
  TFilename& add(const char* n);

  // @cmember Ritorna il nome del file
  const char* name() const;
  // @cmember Ritorna il nome del direttorio
  const char* path() const;
  // @cmember Genera il nome di un file temporaneo
  const TFilename& temp(const char* prefix = NULL);
  // @cmember Genera il nome della directory temporanea
  const TFilename& tempdir();
};


// @doc EXTERNAL

// @class TToken_string | Contiene una stringa formata da piu' stringhe
//                        separate da un carattere (di solito il pipe)
//
// @base public | TString
class TToken_string : public TString
// @author:(INTERNAL) Guido
{
  // @access:(INTERNAL) Private Member

  // @cmember:(INTERNAL) Carattere separatore
  char _separator;
  // @cmember:(INTERNAL) Puntatore all'ultimo
  int _last;

  // @access Protected Member
protected:
  // @cmember Inserisce l'n-esima stringa 
  bool set_item(const char* v, int n);
  
  // @access Public Member
public:
  // @cmember Costruttore
  TToken_string(const char* = "", char separator = '|');
  // @cmember Costruttore
  TToken_string(int n, char separator = '|');
  // @cmember Costruttore
  TToken_string(const TToken_string& s);
  // @cmember Distruttore
  ~TToken_string();

  // @cmember Crea un duplicato della token string
  virtual TObject* dup() const;
  // @cmember Setta il carattere separatore a s
  void separator(char s);

  // @cmember Rimette all'inizio il puntatore
  void restart()
  { _last = empty() ? -1 : 0; }
  // @cmember Assegna una stringa
  const TString& operator =(const char* s)
  { set(s);restart();return *this; }
  // @cmember Assegna una stringa
  const TString& operator =(const TString& s)
  { set(s);restart();return *this; }

  // @cmember Aggiunge una stringa
  void add(const char* s, int n = -1);
  // @cmember Aggiunge un carattere
  void add(char c, int pos = -1);
  // @cmember Aggiunge un long
  void add(long n, int pos = -1);
  // @cmember Aggiunge un intero
  void add(int n, int pos = -1);
  // @cmember Toglie la stringa di posizione pos
  void destroy(int pos);
  // @cmember Ritorna il prossimo token
  const char* get();
  // @cmember Ritorna un token
  const char* get(int n);
  // @cmember Ritorna un carattere (chiama <mf TToken_string::get>)
  char get_char(int n = -1);
  // @cmember Ritorna un intero (chiama <mf TToken_string::get>)
  int get_int(int n = -1);
  // @cmember Ritorna un intero esteso (chiama <mf TToken_string::get>)
  long get_long(int n = -1);
  // @cmember Ritorna la posizione dell'item s
  int get_pos(const char* s);
  // @cmember Ritorna la posizione dell'item s
  int get_pos(long s);
  // @cmember Ritorna il numero di token presenti
  int items() const;
  // @cmember Controlla se tutti i token sono nulli
  bool empty_items() const;
};

///////////////////////////////////////////////////////////
// DES Paragraph
///////////////////////////////////////////////////////////

// @doc EXTERNAL

// @class TParagraph_string | Classe che serve per spezzare le stringhe in paragrafi
//                            lunghi al massimo la lunghezza fissata
//
// @base public | TToken_string
class TParagraph_string : public TToken_string
// @author:(INTERNAL) Guido 
{
  // @access:(INTERNAL) Private Member

  // @cmember:(INTERNAL) Lunghezza massima del paragrafo
  int _width;

  // @access Protected Member
protected:
  // @cmember Spezza la stringa in paragrafi di lunghezza massima fissata
  void tokenize();

  // @access Public Member
public:
  // @cmember Costruttore
  TParagraph_string(const char* s, int width);

  // @cmember Distruttore
  virtual ~TParagraph_string() { }

  // @cmember Assegna una stringa
  const TString& operator =(const char* s);
  // @cmember Assegna un oggetto stringa
  const TString& operator =(const TString & s)
  { return operator=((const char *) s);}
  // @cmember Permette di assegnare la lunghezza massima del paragrafo
  void set_width(int width)
  { _width = width; }
};

///////////////////////////////////////////////////////////
// DES TString_array
///////////////////////////////////////////////////////////

// @doc EXTERNAL

// @class TString_array | Array di stringhe
//
// @base public | TArray
class TString_array : public TArray
// @author:(INTERNAL) Guido
{
  // @access Public Member
public:
  // @cmember Ritorna la stringa n dell'array (se non c'e' ritorna errore)
  TToken_string& row(int n)
  { return (TToken_string&)operator[](n); }
  // @cmember Ritorna la stringa n dell'array (se non c'e' ritorna errore)
  const TToken_string& row(int n) const
  { return (TToken_string&)operator[](n); }
  // @cmember Restituisce il puntatore alla stringa n dell'array (NULL se non esiste)
  TToken_string* rowptr(int n)
  { return (TToken_string*)objptr(n); }
  // @cmember assegnamento di un array
  const TString_array& operator=(const TString_array& a);
  // @cmember Aggiunge una Token string all'array (chiama <mf TArray::add>)
  int add(TToken_string* s, int n = -1)
  { return TArray::add(s, n); }
  // @cmember Aggiunge un oggetto stringa all'array (chiama <mf TArray::add>)
  int add(const TToken_string& s, int n = -1);
  // @cmember Aggiunge una stringa all'array (chiama <mf TArray::add>)
  int add(const char* s, int n = -1);
  // @cmember Cerca una stringa nell'array
  int find(const char* s, int from = 0) const;
  // @cmember Ordina alfabeticamente l'array
  void sort(bool ascendig = TRUE);

  // @cmember Costruttore
  TString_array(int size = 8) : TArray(size)
  {}
  // @cmember Distruttore
  virtual ~TString_array()
  {}
};

#endif