#ifndef __RELATION_H
#define __RELATION_H

#ifndef __ISAM_H
#include <isam.h>
#endif

#ifndef __SORT_H
class TSort;
#endif

// @doc EXTERNAL

// @class TRelation | Classe per la definizione delle relazioni esistenti tra i file
//
// @base public | TObject
class TRelation : public TObject
// @author:(INTERNAL) Alex
{
  // @cfriend TRelationdef
  friend class TRelationdef;
  // @cfriend TRelation_description
  friend class TRelation_description;
  // @cfriend TCursor
  friend class TCursor;

// @access:(INTERNAL) Private Member

  // @cmember:(INTERNAL) Stato della relazione
  TToken_string _status;
  // @cmember:(INTERNAL) Array dei descrittori dei file
  TArray _files;
  // @cmember:(INTERNAL) Array di <c TRelationdef>
  TArray _reldefs;
  // @cmember:(INTERNAL) Codice dell'ultimo errore occorso
  int _errors;     

// @access Protected Member
protected:
  // @cmember Ritorna l'indice di <p _files> del numero logico passato
  int log2ind(int logicnum) const;
  // @cmember Ritorna l'indice di <p _files> del alias del file passato
  int alias2ind(int alias) const;
  // @cmember Ritorna l'indice di <p _files> del nome del file passato
  int name2ind(const char* name) const;

  // @cmember Ritorna la <c TRelationdef> <p i>-esima
  TRelationdef& reldef(int i) const
  { return (TRelationdef&)_reldefs[i]; }
  // @cmember Ritorna il descrittore del file <p i>-esimo
  TLocalisamfile& file(int i = 0) const
  { return (TLocalisamfile&)_files[i]; }

  // @cmember Permette di posizionare l'albero di relazioni tra i file
  int position_rels(TIsamop op = _isequal, TReclock lockop = _nolock, int first = 0);

// @access Public Member
public:  // TObject
  // @cmember Controlla se si tratta di un oggetto valido
  virtual bool ok() const
  { return good(); }
  // @cmember Permette di stampare l'oggetto su <p out>
  virtual void print_on(ostream& out) const;      
  
public:
  // @cmember Aggiorna l'albero delle relazioni
  int update(int first = 0)
  { return position_rels(_isequal, _nolock, first); }
  // @cmember Azzera l'albero delle relazioni
  void zero();
  //@cmember Sposta la relazione sul record successivo del file principale (chiama <mf TRelation::position_rels>)
  virtual int next(TReclock lockop = _nolock)
  { return file().next(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); }
  //@cmember Sposta la relazione sul record precedente del file principale (chiama <mf TRelation::position_rels>)
  virtual int prev(TReclock lockop = _nolock)
  { return file().prev(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); }
  //@cmember Sposta la relazione sul primo record del file principale (chiama <mf TRelation::position_rels>)
  virtual int first(TReclock lockop = _nolock)
  { return file().first(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); }
  //@cmember Sposta la relazione sull'ultimo record del file principale (chiama <mf TRelation::position_rels>)
  virtual int last(TReclock lockop = _nolock)
  { return file().last(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); }
  //@cmember Salta <p nrec> posizione dalla corrente sul file principale (chiama <mf TRelation::position_rels>)
  virtual int skip(TRecnotype nrec, TReclock lockop = _nolock)
  { return file().skip(nrec, lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); }
  //@cmember Legge il record (chiama <mf TRelation::position_rels>)
  virtual int read(TIsamop op = _isgteq, TReclock lockop = _nolock)
  { return file().read(op, lockop) == NOERR ? position_rels(_isequal, lockop) : file().status();}

  // @cmember Ritorna il descrittore del file
  TLocalisamfile& lfile(int logicnum = 0) const;
  // @cmember Ritorna il descrittore del file
  TLocalisamfile& lfile(const char* name) const;
  // @cmember Ritorna il descrittore del file (chiama <mf TRelation::lfile>)
  TLocalisamfile& operator[] (int logicnum) const 
  { return lfile(logicnum); }

  // @cmember Abilita/disabilita la scrittura dei record collegati sul file
  void write_enable(int logicnum = 0, const bool on = TRUE) ;
  // @cmember Abilita/disabilita la scrittura sul file
  void write_enable(const char* name, const bool on = TRUE) ;
  // @cmember Disabilita la scrittura sul file (chiama <mf TRelation::write_enable>)
  void write_disable(int logicnum = 0) 
  { write_enable(logicnum, FALSE); }
  // @cmember Disabilita la scrittura sul file (chiama <mf TRelation::write_enable>)
  void write_disable(const char* name) 
  { write_enable(name, FALSE); }

  // @cmember Ritorna il record corrente del file <p logicnum>
  //          (chiama <mf TRelation::lfile>)
  TRectype& curr(int logicnum = 0) const 
  { return lfile(logicnum).curr(); }
  // @cmember Posiziona il numero logico sul record successivo
  bool next_match(int logicnum,  const char* fieldlist = NULL, int nkey = 0);

  // @cmember Aggiunge una nuovo file alla relazione partendo dal descrittore del file
  bool add(TLocalisamfile* f, const char* relexprs, int key = 1, int linkto = 0, int alias = 0, bool allow_lock = FALSE);
  // @cmember Aggiunge una nuovo file alla relazione partendo dal numero logico del file
  bool add(int logicnum, const char* relexprs, int key = 1, int linkto = 0, int alias = 0, bool allow_lock = FALSE);
  // @cmember Aggiunge una nuovo file alla relazione partendo dal nome della tabella
  bool add(const char* tabname, const char* relexprs, int key = 1, int linkto = 0, int alias = 0, bool allow_lock = FALSE);
  // @cmember Sostituisce nella relazione il file  di indice index
  void replace(TLocalisamfile* f, int index = 0,const char * relexprs="",int key=1);
  // @cmember Sostituisce nella relazione il file di ID lognum
  void replacef(TLocalisamfile* f, int lognum = 0,const char * relexprs="",int key=1);

  // @cmember Aggiunge il record corrente
  virtual int write (bool force = TRUE);
  // @cmember Riscrive il record corrente
  virtual int rewrite (bool force = TRUE);
  // @cmember Elimina il record corrente
  virtual int remove ();

  // @cmember Controlla se e' stata raggiunta la fine del file
  //          (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )
  bool eof( int logicnum = 0) const
  { return lfile(logicnum).eof(); }
  // @cmember Controlla se e' stata raggiunta l'inizio del file
  //          (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )
  bool bof( int logicnum = 0) const
  { return lfile(logicnum).bof(); }
  // @cmember Ritorna lo stato del file indicato (se <p logicnum> = 0 dell'intera relazione, 
  //          altrimenti del file indicato )
  int status(int logicnum = 0) const
  { return lfile(logicnum).status(); }
  // @cmember Controlla se l'ultima operazione sul file e' stata effettuata correttamente
  //          (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )
  bool good( int logicnum = 0) const
  { return lfile(logicnum).good(); }
  // @cmember Controlla se l'ultima operazione sul file ha generato un errore
  //          (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )
  bool bad( int logicnum = 0) const
  { return lfile(logicnum).bad(); }
  // @cmember Controlla se e' il file e' vuoto
  //          (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )
  bool empty( int logicnum = 0) const
  { return lfile(logicnum).empty(); }

  // @cmember Controlla se la relazione e' corretta
  bool isconsistent (bool reset = FALSE);

  // @cmember Controlla se c'e' un record ed e' il primo match (non si e' mai fatta
  //          <mf TRelation::position_rels>)
  bool is_first_match(int logicnum);

  // @cmember Ritorna il numero di files collegati
  int items()
  { return _reldefs.items(); }
  
  // @cmember Ritorna TRUE se il file <p logicnum> e' nella relazione
  bool exist(int logicnum) const;

  // @cmember Salva la posizione attuale di tutti i file della relazione
  void save_status () ;
  // @cmember Ripristina la posizione attuale di tutti i file della relazione
  void restore_status () ;
  
  // positioning operators. return status
  // @cmember Sposta il puntatore corrente di <p npos> posizioni in avanti
  //          (ritorna lo stato)
  TRecnotype operator +=(const TRecnotype npos)
  { return skip(npos);  }
  // @cmember Sposta il puntatore corrente di <p npos> posizioni in dietro
  //          (ritorna lo stato)
  TRecnotype operator -=(const TRecnotype npos)
  { return skip(-npos); }
  // @cmember Sposta il puntatore corrente di una posizione in avanti
  //          (ritorna lo stato)
  TRecnotype operator ++()
  { return next(); }
  // @cmember Sposta il puntatore corrente di una posizione in dietro
  //          (ritorna lo stato)
  TRecnotype operator --()
  { return prev(); }
  
  // @cmember Costruttore dal numero logico del file
  TRelation(int logicnum);
  // @cmember Costruttore dal nome della tabella
  TRelation(const char* tabname);
  // @cmember Costruttore dal nome del file
  TRelation(TLocalisamfile* f);

  // @cmember Distruttore
  virtual ~TRelation();
};


class TExpression;

// @doc EXTERNAL

// @type FILTERFUNCTION | Prototipo funzione che controlla se il record debba essere incluso nel cursore
typedef bool (*FILTERFUNCTION)(const TRelation* r);

// @doc EXTERNAL

// @class TCursor | Classe per la definizione di un cursore su di una relazione
//
// @base public | TContainer
class TCursor : public TContainer

// @author:(INTERNAL) Villa

// @access:(INTERNAL) Private Member
{
  // @cmember:(INTERNAL) Relazione su cui costruire il cursore
  TRelation* _if;
  // @cmember:(INTERNAL) Chiave del file principale
  int _nkey;
  // @cmember:(INTERNAL) Posizione corrente
  TRecnotype _pos;
  // @cmember:(INTERNAL) Numero totale di record che verificano il filtro
  TRecnotype _totrec;
  // @cmember:(INTERNAL) Numero dell'ultimo record
  TRecnotype _lastrec;
  // @cmember:(INTERNAL) Chiave dell'ultimo record
  TRecnotype _lastkrec; 
  // @cmember:(INTERNAL) Ditta di creazione indice
  long _index_firm;
  // @cmember:(INTERNAL) Nome assoluto del file principale
  TFilename _filename;
  // @cmember:(INTERNAL) Filtro definito con la <mf TCursor::setfilter>
  TString _filter;
  // @cmember:(INTERNAL) Nome della chiave iniziale
  TString _keyfrom;
  // @cmember:(INTERNAL) Nome della chiave finale
  TString _keyto;
  // @cmember:(INTERNAL) Espressione del filtro relativo
  TExpression* _fexpr;
  // @cmember:(INTERNAL) Array di fieldref contente i campi interessati al filtro
  TArray  _frefs;
  // @cmember:(INTERNAL) Indica se e' stata messa in attesa (non puo' essere modificato)
  bool _frozen;
  // @cmember:(INTERNAL) Flag che permette l'update della relazione per l'espressione-filtro
  bool _filter_update;
  // @cmember:(INTERNAL) Flag che permette l'update della relazione per la funzione-filtro
  bool _filterfunction_update;
  // @cmember:(INTERNAL) Livello max per l'update della relazione per la espressione-filtro
  int _filter_limit;
  // @cmember:(INTERNAL) Funzione filtro
  FILTERFUNCTION _filterfunction;
  // @cmember:(INTERNAL) Nome del file indice
  TFilename _indexname;

  // @cmember:(INTERNAL) Crea (o aggiorna) effettivamente l'indice del cursore
  TRecnotype update();

// @access Protected Member
protected:
  // @cmember Apre il file di indice
  FILE* open_index(bool create = FALSE);
  // @cmember Chiude il file di indice
  void close_index(FILE* f);
  // @cmember Ritorna se e' stato modificato il cursore (cioe' quando occorre fare l'update)
  virtual bool changed();
  // @cmember Costruisce il cursore a partire dal record
  virtual TRecnotype buildcursor(TRecnotype rp);
  // @cmember Permette di creare una pagina di cursori
  virtual int filtercursor(int pagecnt, TRecnotype* page);
  // Controlla se una chiave rispetta il filtro
  bool simple_filtercursor(const char* key) const;
  // @cmember Posiziona il cursore in modo che il record corrente corrisponda alla 
  //          posizione dell'indice temporaneo
  TRecnotype readrec();
  // @cmember Setta il filtro sul cursore
  void filter(const char* filter, const TRectype* from = NULL, const TRectype* to = NULL, int tilde = 0x0);
  // @cmember Indica se e' possibile fare l'update sulla relazione (se e' possibile
  //        sia sull'espressione-filtro che sulla funzione-filtro)
  bool update_relation() const 
  { return (_filter_update || _filterfunction_update); }
  
  int filter_limit() const { return _filter_limit; }
  
// @access Public Member
public:
  // @cmember Si sposta alla posizione <p nr>
  TRecnotype operator =(const TRecnotype nr);
  // @cmember Si sposta di <p nr> posizioni dalla corrente in avanti
  TRecnotype operator +=(const TRecnotype nr);        
  // @cmember Si sposta di <p nr> posizioni dalla corrente in dietro
  TRecnotype operator -=(const TRecnotype npos) 
  { return operator +=(-npos); }
  // @cmember Ritorna il primo oggetto del cursor
  TObject* first_item( )
  { operator =( 0 ); return &curr( ); }
  // @cmember Ritorna l'oggetto del cursor successivo al corrente
  TObject* succ_item( )
  { operator +=( 1 ); return &curr( ); }
  // @cmember Ritorna l'oggetto del cursor precedente al corrente
  TObject* pred_item( )
  { operator -=( 1 );  return &curr( );}
  // @cmember Ritorna l'ultimo oggetto del cursor
  TObject* last_item( )
  { operator =( items( ) -1 );  return &curr( ); }
  // @cmember Ritorna il numero di oggetti del cursor
  long objects( ) 
  { return items( ); }
  
  // @cmember Ritorna la posizione corrente
  TRecnotype& pos() 
  { return _pos; }
  // @cmember  Ritorna il numero totale di record
  TRecnotype items();
  // @cmember Ritorna la dimensione del file principale
  TRecnotype size() const 
  { return file().eod(); }

  // @cmember Ritorna il nome della chiave iniziale
  const TString& from() const 
  { return _keyfrom; }
  // @cmember Ritorna il nome della chiave finale
  const TString& to() const 
  { return _keyto; }

  // @cmember Ritorna il descrittore del file principale
  TRectype& curr(int log = 0) const 
  { return _if->curr(log); }
  // @cmember Ritorna il descrittore della tabella
  TRectype& curr(const char * tab) const 
  { return _if->lfile(tab).curr(); }
  //@cmember Testa la presenza di un record senza spostare il cursore
  int test(TIsamop op = _isequal, TReclock lockop = _nolock) const;
  // @cmember Legge il record
  virtual TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock);
  // @cmember Mette un lock sul record
  int lock(TReclock = _lock);
  // @cmember Toglie un lock sul record (chiama <mf TCursor::lock>)
  int unlock() 
  { return lock(_unlock); }

  // @cmember Controlla che si tratti di un oggetto valido
  virtual bool ok() const;
  // @cmember Ritorna il filtro
  const char* filter() const 
  { return _filter; }
  // @cmember Permette di mettere in attesa il cursore
  void freeze(bool on = TRUE) 
  { _frozen = on; }
  // @cmember Controlla se il cursore e' congelato
  bool frozen() const 
  { return _frozen; }
  // @cmember Permette di modificare l'espressione-filtro
  void setfilter(const char* filter_expr, bool update=FALSE, int limit = 0) 
  { filter(filter_expr); _filter_update = update; _filter_limit = limit; }
  // @cmember Setta la regione-filtro dal record <p from> al record <p to>
  void setregion(const TRectype& from, const TRectype& to, int tilde = 0x0)
  { filter(NULL,&from, &to, tilde); }

  // @cmember Ritorna la relazione del cursore
  TRelation* relation() const 
  { return _if; }
  // @cmember Ritorna il file della relazione con numero logico <p lnum>
  TLocalisamfile& file(int lnum = 0) const 
  { return _if->lfile(lnum); }
  // @cmember Ritorna il file della relazione con nome <p name>
  TLocalisamfile& file(const char* name) const 
  { return _if->lfile(name); }
  // @cmember Riposiziona l'albero delle relazione (chiama <mf TRelation::position_rels>)
  int repos() 
  { return _if->position_rels(); }

  // @cmember Ritorna l'espressione-filtro
  TExpression* expression() const 
  { return _fexpr; }
  // @cmember Ritorna l'array di fieldref contenete i nomi dei campi del filtro
  const TArray & field_refs() const 
  { return _frefs; }
  // @cmember Ritorna la funzione-filtro
  FILTERFUNCTION filterfunction() const 
  { return _filterfunction; }

  // @cmember Setta la chiave del file principale alla chiave del cursore
  void setkey() 
  { file().setkey(_nkey); }
  // @cmember Setta la chiave del file principale alla chiave del cursore
  void setkey(int nkey);
  // @cmember Ritorna la chiave del cursor
  int key() const 
  { return _nkey; }

  // @cmember Posiziona il file <p lognum> sul record successivo (chiama <mf TRelation::next_match> o ++(*this) se � il file principale)
  bool next_match(int lognum, const char* fl = NULL, int nk = 0);
  // @cmember Controlla se c'e' un record ed e' il primo match (chiama <mf TRelation::is_first_match>)
  bool is_first_match(int ln);
  
  // @cmember Setta la funzione-filtro
  void set_filterfunction(FILTERFUNCTION ff, bool update=FALSE) 
  { _filterfunction = ff; _lastrec = 0L; _filterfunction_update = update;}
  // @cmember Controlla se esiste un filtro sul cursor
  bool has_filter() const 
  { return _filter.not_empty() || _filterfunction; }
  bool has_simple_filter() const;

  // @cmember Salva la posizione attuale di tutti i file del cursore
  void save_status() 
  { _if->save_status(); }
  // @cmember Ripristina la posizione attuale di tutti i file del cursore
  void restore_status() 
  { _if->restore_status(); }

  // @cmember Costruttore
  TCursor(TRelation* f, const char* filter = "", int key = 1, const TRectype* from = NULL, const TRectype* to = NULL, int tilde = 0x0);
  // @cmember Distruttore
  virtual ~TCursor();
};


// @doc EXTERNAL

// @class TSorted_cursor | Costruisce e gestisce un cursore ordinato per chiavi diverse da quelle specificate nel file.
class TSorted_cursor : public TCursor

// @author:(INTERNAL) Angelo

// @comm Il formato dell'espressione deve essere: [LF->]FIELDNAME[[from,to]][+<pipe>-]... Inoltre tutta l'espressione puo' essere racchiusa
//       dall'operatore UPPER(), per controlli non case-sensitive. 
//       <nl><p FIELDNAME> e' il nome del campo per quale si vuole effettuare il sort, LF indica il numero logico del file (appartenente alla relazione!).
//       <nl><p from> e <p to> sono parametri opzionali usati per specificare un sottocampo. Per default prende l'intera lunghezza.
//       <nl><p +> e <p -> sono parametri opzionali usati per specificare il tipo di ordinamento: <p +> significa crescente, <p -> significa 
//       decrescente. Per default l'ordinamento e' crescente. E' cosi' possibile creare chiavi con campi non appartenenti al
//       file principale della relazione.
//       <nl>Es. "CODCF-<pipe>TIPOCF<pipe>SOTTOCONTO+<pipe>UPPER(20->RAGSOC[1,40]-)"

// @access:(INTERNAL) Private Member
{
  // @cmember:(INTERNAL) Espressione per l'ordinamento
  TToken_string _order_expr;
  // @cmember:(INTERNAL) Puntatore all'oggetto per ordinare il cursore (vedi <c TSort>)
  TSort* _sort; 
  // @cmember:(INTERNAL) Indica se l'espressione e' cambiata
  bool _is_changed_expr;        
  // @cmember:(INTERNAL) Indica se l'espressione e' valida
  bool _is_valid_expr;
  
// @access Protected Member
protected:     
  // @cmember Controlla la validita' dell'espressione
  bool check_expr(TString& s);                                            
  // @cmember Controlla se la singola espressione contiene l'operatore UPPER(), ritornandone l'argomento
  bool is_upper(TString& s);
  // @cmember Costruisce una stringa con la chiave di sort del record corrente
  const char* fill_sort_key(char* k);

  // @cmember Costruisce il cursore a partire dal record (vedi <c TCursor>)
  virtual TRecnotype buildcursor(TRecnotype rp);
  // @cmember Permette di creare una pagina di cursori (vedi <c TCursor>)
  virtual int filtercursor(int pagecnt, TRecnotype* page);
  // @cmember Ritorna se e' stato modificato il cursore (cioe' quando occorre fare l'update) (vedi <c TCursor>)
  virtual bool changed();
  
// @access Public Member
public: 
  // @cmember Si sposta alla posizione <p nr>
  TRecnotype operator =(const TRecnotype nr) 
  { return TCursor::operator =(nr); }
  // @cmember Trova l'indice del record corrente
  virtual TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock);

  // @cmember Permette di cambiare l'ordinamento del cursore.
  void change_order(const char* order_expr);                                           
  
  // @cmember Costruttore
  TSorted_cursor(TRelation *f,const char * order_expr, const char * filter = "", int key = 1, const TRectype* from = NULL, const TRectype* to = NULL);
  // @cmember Distruttore
  virtual ~TSorted_cursor();
};

// @doc EXTERNAL

// @class TFieldref | Classe per la definizione di riferimenti ad un campo di una relazione
//
// @base public | TObject
class TFieldref : public TObject

// @author:(INTERNAL) Guido

// @access:(INTERNAL) Private Member
{
  // @cmember:(INTERNAL) Numero del file
  short _fileid;      
  // @cmember:(INTERNAL) Nome tabella o stringa col numero del file
  TString _id;
  // @cmember:(INTERNAL) Nome del campo
  TString _name;
  // @cmember:(INTERNAL) Sottostringa di partenza
  int _from;
  // @cmember:(INTERNAL) Sottostringa di arrivo
  int _to;

// @access Protected Member
protected:
  // @cmember Stampa l'oggetto
  virtual void print_on(ostream& out) const;
  // @cmember Duplica l'oggetto TFieldref
  virtual TObject* dup() const;
  
  void copy(const TFieldref& fr);

// @access Public Member
public:
  // @cmember Costruttore
  TFieldref();
  // @cmember Costruttore
  TFieldref(const TString&, short defid);
  // @cmember Costruttore
  TFieldref(const TFieldref& f) { copy(f); }

  // @cmember Operatore di assegnamento
  TFieldref& operator =(const TString& s);
  // @cmember Operatore di assegnamento
  TFieldref& operator =(const TFieldref& f) { copy(f); return *this; }
  
  // @cmember Controlla la validita' dell'oggetto (TRUE se il numero del file e' valido)
  virtual bool ok() const 
  { return _name.not_empty(); }

  // @cmember Ritorna il numero del file
  int file() const 
  { return _fileid; }
  // @cmember Setta il numero del file
  void set_file(int f);
  
  // @cmember Ritorna il nome del campo
  const TString& name() const 
  { return _name; }
  // @cmember Setta il nome del campo
  void set_name(const char* n) 
  { _name = n; }
  // @cmember Setta <p from>
  void set_from(int f) 
  { if (f > 0) f--; else f = 0; _from = f; }
  // @cmember Setta <p to>
  void set_to(int t) 
  { _to = t; }

  // @cmember Ritorna <p from>
  int from() const 
  { return _from; }
  // @cmember Ritorna <p to>
  int to() const 
  { return _to; }
  // @cmember Ritorna la lunghezza del campo di <p TRectype>
  int len(const TRectype &rec) const;

  // @cmember Cerca nel record il campo e ne ritorna il contenuto
  const char* read(const TRectype&) const;
  // @cmember Cerca nel record il campo e vi scrive <p val>
  void write(const char* val, TRectype& rec) const;

  // @cmember Cerca nella relazione il campo e ne ritorna il contenuto
  const char* read(const TRelation&) const;
  // @cmember Cerca nella relazione il campo e vi scrive <p val>
  void write(const char* val, TRelation&) const;

  // @cmember Cerca nel file .ini il campo e ne ritorna il valore
  const char* read(TConfig& ini, const char* defpar) const;
  // @cmember Cerca nel file .ini il campo e vi scrive <p val>
  void write(TConfig& ini, const char* defpar, const char* val) const;
};                          

int name2log(const char* name);

// @doc INTERNAL

// @class TRelation_description | Gestisce l'uso interattivo di una relazione (scelta campi, descrizione)
//
// @base public | TObject
class TRelation_description : public TObject

// @author:(INTERNAL) Guido

// @access:(INTERNAL) Private Member
{       
  // @cmember:(INTERNAL) Relazione descritta
  TRelation* _rel;
  // @cmember:(INTERNAL) Nome dei files della relazione
  TString_array _files;  
  // @cmember:(INTERNAL) Array di campi
  TArray _fields;  
  // @cmember:(INTERNAL) Numero logico del file corrente
  int _cur_file;
  // @cmember:(INTERNAL) Numero del campo corrente
  int _cur_field;
  // @cmember:(INTERNAL) UNUSED
  bool _menu;
  // @cmember:(INTERNAL) File corrente
  TToken_string _cfile;
  // @cmember:(INTERNAL) Campo corrente
  TToken_string _cfield;
  
// @access Protected Member
protected:
  // @cmember Inizializza l'array di stringhe con i nomi dei files
  void init_files_array();
  // @cmember Legge la relazione
  void read_rel();                   
  
// @access Public Member
public:
  // @cmember Controlla se si tratta di un oggetto valido (se il numero dei files e' <gt> di 0)
  virtual bool ok() const 
  { return _files.items() > 0; }

public:
  
  // @cmember Seleziona il file <p id>
  bool choose_file (int id = 0);
  // @cmember Setta come file corrente quello con numero logico <p id>
  bool set_cur_file(int id = 0);

  // @cmember Seleziona il campo <p fld> del file selezionato
  bool choose_field(const char* fld = "");                         
  
  // @cmember Costruisce un menu'
  bool build_menu(const char* title = "Database");               
  // @cmember Rimuove il menu' costruito con <mf TRelation_description::build_menu>
  bool remove_menu();        
  
  // @cmember Ritorna il numero logico del file selezionato (vedi <mf TRelation_description::choose_file>)
  int file_num();
  // @cmember Ritorna la descrizione del file selezionato (vedi <mf TRelation_description::choose_file>)
  const char* file_desc();
  // @cmember Setta la descrizione del file selezionato
  void file_desc(const char* desc);
  // @cmember Setta la descrizione del campo
  bool set_field_description(const char* field, const char* des);
  // @cmember Ritorna la descrizione del campo
  const char* get_field_description(const char* field);

  // @cmember Ritorna la descrizione del campo selezionato (vedi <mf TRelation_description::choose_file>)
  const char* field_desc();
  // @cmember Setta la descrizione del campo selezionato
  void field_desc(const char* desc);
  // @cmember Ritorna il nome del campo selezionato (vedi <mf TRelation_description::choose_field>)
  const char* field_name();
  // @cmember Ritorna la lunghezza del campo selezionato (vedi <mf TRelation_description::choose_field>)
  int field_len();
  // @cmember Ritorna il tipo del campo selezionato (vedi <mf TRelation_description::choose_field>)
  TFieldtypes field_type();
  
  // @cmember Ritorna l'array di tutti nomi dei files
  const TString_array& get_all_desc() const 
  { return _files; }
  // @cmember Cambia la relazione descritta
  void change_relation(TRelation& rel, TString_array& arr);
  
  // @cmember Stampa l'oggetto
  virtual void print_on(ostream& out) const;
  
  // @cmember Costruttore
  TRelation_description(TRelation& r);
  // @cmember Distruttore
  virtual ~TRelation_description(); 

// @devnote Domani o doman l'altro gestira' l'editing interattivo e grafico
};

// @doc EXTERNAL

// @class TSortedfile | Classe per la definizione di ordinamenti arbitrari sui file isam
//
// @base public | TLocalisamfile
//
// @author:(INTERNAL) Augusto
class TSortedfile : public TLocalisamfile
{
  TRelation * _rel;
  TSorted_cursor * _curs;
  // @access:(INTERNAL) Private Member

// @access Protected Members
protected:
  // @cmember Apre il file con lock (vedi <mf TBaseisamfile::_open>)
  int open(unsigned int mode = _manulock);
  // @cmember Chiude il file aperto
  int close() ;

// @access Public Members
public:
  // @cmember Avanza di <p npos> record
  virtual int operator +=(const TRecnotype npos);
  // @cmember Sposta indietro di <p npos> record
  virtual int operator -=(const TRecnotype npos);
  // @cmember Avanza al record successivo
  virtual int operator ++();
  // @cmember Indietreggia al record precedente
  virtual int operator --();
  // @cmember Ritorna TRUE se tabella
  virtual bool tab() const 
  { return FALSE;}

  // @cmember Ritorna il record corrente del del file 
  virtual TRectype& curr() const; 
  // @cmember Azzera tutti i record del cursore
  virtual void zero() { _rel->zero(); }
  // @cmember Sostituisce il record corrente del del file (disallocando il vecchio)
  virtual void set_curr(TRectype * curr); 
  // @cmember Si posiziona sul primo record del file (vedi <t TReclock>)
  virtual int first(word lockop = _nolock);
  // @cmember Si posiziona sull'ultimo record del file (vedi <t TReclock>)
  virtual int last(word lockop = _nolock);
  // @cmember Si posiziona sul successivo record del file (vedi <t TReclock>)
  virtual int next(word lockop = _nolock);
  // @cmember Si posiziona sul precedente record del file (vedi <t TReclock>)
  virtual int prev(word lockop = _nolock);
  // @cmember Rilegge l'ultimo record letto (vedi <t TReclock>)
  virtual int reread(word lockop = _nolock);
  // @cmember Rilegge l'ultimo record letto e lo copia in <p rec> (vedi <t TReclock>)
  virtual int reread(TRectype& rec, word lockop = _nolock);
  // @cmember Salta <p nrec> record dalla posizione corrente (vedi <t TReclock>)
  virtual int skip(TRecnotype nrec, word lockop = _nolock);
  // @cmember Legge il record (vedi <t TReclock> e <t TIsamop>)
  virtual int read(word op = _isequal, word lockop = _nolock);
  // @cmember Legge il record e lo copia in <p rec> (vedi <t TReclock> e <t TIsamop>)
  virtual int read(TRectype& rec, word op = _isequal, word lockop = _nolock);
  // @cmember Legge il record alla posizione  <p nrec> (vedi <t TReclock>)
  virtual int readat(TRecnotype nrec, word lockop = _nolock);
  // @cmember Legge il record alla posizione <p nrec> e lo copia in <p rec> (vedi <t TReclock>)
  virtual int readat(TRectype& rec, TRecnotype nrec, word lockop = _nolock);
  // @cmember Aggiunge un record
  virtual int write();
  // @cmember Aggiunge un record copiando da <p rec>
  virtual int write(const TRectype& rec);
  // @cmember Riscrive un record
  virtual int rewrite();
  // @cmember Riscrive un record (il record <p rec>)
  virtual int rewrite(const TRectype& rec);
  // @cmember Riscrive un record alla posizione <p nrec>
  virtual int rewriteat(TRecnotype nrec);
  // @cmember Riscrive un record alla posizione <p nrec> copiando da <p rec>
  virtual int rewriteat(const TRectype& rec, TRecnotype nrec);
  // @cmember Elimina il record
  virtual int remove();
  // @cmember Elimina il record copiando da <p rec>
  virtual int remove(const TRectype& rec);
  // @cmember 
  virtual TRecnotype eod() const ;
  // @cmember 
  virtual bool empty();
  // @cmember Ritorna il numero del record corrente
  virtual TRecnotype recno() const 
  {return _curs->pos();}
  // @cmember setta la chiave 
  void setkey(int nkey);
  // @cmember Resetta la regione del file (chiama <p TCursor::setregion>
  void setregion(const TRectype &f, const TRectype &t, int tilde = 0x0);

  // TO REMOVE
  TRelation& relation()  
  { return *_rel; }
  // TO REMOVE
  TSorted_cursor &cursor() 
  { return *_curs; }
  
  // @cmember Restituisce se il file � ordinato con indice esterno (default:FALSE)
  virtual bool is_sorted()
  {return TRUE;}
  // @cmember Costruttore. 
  TSortedfile(int logicnum,TRelation* rel = NULL,const char* ordexpr="",const char * filter="", int nkey=1);
  // @cmember Distruttore
  virtual ~TSortedfile();
};



#endif
// ** EOF relation.h