#ifndef __RECARRAY_H
#define __RECARRAY_H

#ifndef __ASSOC_H
#include <assoc.h>
#endif

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

///////////////////////////////////////////////////////////
// TRecord_Array
///////////////////////////////////////////////////////////

// @doc EXTERNAL

// @class TRecord_array | Classe per la gestione di un array di record
//
// @base public | TArray
class TRecord_array : private TArray

// @author:(INTERNAL) Guido

// @access:(INTERNAL) Private Member
{ 
  // @cmember:(INTERNAL) Numero logico del file principale
  int _file;
  // @cmember:(INTERNAL) Offset iniziale del record array
  int _offset;
  // @cmember:(INTERNAL) Nome del campo col numero di riga
  TString16 _num;

// @access Protected Member
protected:
  // @cmember Ritorna il numero riga del record <p r>
  int rec2row(const TRectype& r) const;
  // @cmember Ritorna il nome del campo con numero di riga
  const TString& num_field() const 
  { return _num; }
  // @cmember Elimina il record di posizione <p i> (ritorna il risultato dell'operazione)
  int remove_from(int i) const;
  // @cmember Confronta i campi della chiave 1 scartando l'ultimo
  bool good(const TRectype& rec) const;

// @access Public Member
public:
  // @cmember Ritorna il record che fa da chiave per tutti gli altri
  const TRectype& key() const;
  // @cmember Ritorna il numero di righe presenti
  int rows() const 
  { return items()-1; }
  
  // @cmember Ritorna la riga successiva non vuota a partire da <p r>
  int succ_row(int r) const 
  { return succ(r - _offset) + _offset; }
  // @cmember Ritorna la riga precedente non vuota a partire da <p r>
  int pred_row(int r) const 
  { return pred(r - _offset) + _offset; };
  // @cmember Ritorna l'ultma riga non vuota
  int last_row() const 
  { return last() + _offset; }
  // @cmember Ritorna la prima riga non vuota
  int first_row() const 
  { return succ_row(0); }
  
  // @cmember Ritorna il record <p r>-esimo
  const TRectype& row(int r) const
  { CHECKD(r > _offset, "Bad record number ", r); return (const TRectype&)operator[](r - _offset); }
  
  // @cmember Controlla se esiste la riga <p r> (TRUE se esiste)
  bool exist(int r) const;
  // @cmember Ritorna la riga <p r>-esima; se tale riga non esiste e se <p create> assume il valore TRUE la riga viene creata 
  TRectype& row(int r, bool create);
 
  // @cmember Inserisce una riga alla posizione indicata nel record, sposta gli altri elementi se la posizione era gia' occupata
  virtual int insert_row(TRectype* r);
  // @cmember Inserisce una riga alla posizione indicata nel record, sposta gli altri elementi se la posizione era gia' occupata
  int insert_row(const TRectype& r) 
  { return insert_row((TRectype*)r.dup()); }

  // @cmember Aggiunge/sostituisce una riga alla posizione indicata nel record 
  virtual int add_row(TRectype* r);
  // @cmember Aggiunge/sostituisce una riga alla posizione indicata nel record
  int add_row(const TRectype& r) 
  { return add_row((TRectype*)r.dup()); }
  // @cmember Compatta le righe piene
  virtual void pack() ;
  // @cmember Cancella una riga identificata da <p n>
  virtual bool destroy_row(int n, bool pack = FALSE);
  // @cmember Cancella una riga identificata da <p r>
  virtual bool destroy_row(const TRectype& r, bool pack = FALSE) 
  { return destroy_row(rec2row(r), pack); }
  // @cmember Cancella tutte le righe
  void destroy_rows();
  
  // @cmember Ritorna il numero logico del file principale
  int logic_num() const
  { return _file; }
  // @cmember Cambia l'intera chiave (solo se vuoto)
  void set_key(TRectype* r);
  // @cmember Rinumera il campo chiave in seguito a reinsert
  bool renum_key(const char* field, const TString& num);
  // @cmember Rinumera il campo chiave in seguito a reinsert
  bool renum_key(const char* field, long num);

  // @cmember Legge tutto l'array dal file
  virtual int read(const TRectype& r);
  // @cmember Legge tutto l'array dal file
  virtual int read(TRectype* r);
  // @cmember Aggiorna il file (se <p re> == TRUE allora viene aggiornato il record se esisteva)
  virtual int write(bool re = FALSE) const;
  // @cmember Aggiorna il record sul file
  virtual int rewrite() const 
  { return write(TRUE); }
  // @cmember Cancella tutti i record dal file
  virtual int remove() const;
  
  // @cmember Costruttore
  TRecord_array(const TRectype& r, const char* numfield, int first = 1);
  // @cmember Costruttore
  TRecord_array(int logicnum, const char* numfield, int first = 1);
  // @cmember Costruttore
  TRecord_array(const TRecord_array& a);
  // @cmember Distruttore
  virtual ~TRecord_array();
};

///////////////////////////////////////////////////////////
// TFile_cache
///////////////////////////////////////////////////////////

class TFile_cache : private TAssoc_array
{ 
  TToken_string _code;
  TLocalisamfile* _file;
  int _key;
  long _last_firm;

private:
  void init_file();
  void test_firm();
  
protected:
  const TObject& query(const char* chiave);
  virtual TObject* rec2obj(const TRectype& rec) const pure;
  
public:            
  int fill();

  TFile_cache(int num, int key = 1);
  TFile_cache(const char* table, int key = 1);
  virtual ~TFile_cache();
};

class TDecoder : public TFile_cache
{                                                
  TString16 _outf;

protected:
  TObject* rec2obj(const TRectype& rec) const;
  
public:
  const TString& decode(const char* code);
  const TString& decode(long code);

  TDecoder(int num, const char* field, int key = 1);
  TDecoder(const char* table, const char* field = "S0", int key = 1);
  virtual ~TDecoder() { }
};

class TRecord_cache : public TFile_cache
{                                                
protected:
  TObject* rec2obj(const TRectype& rec) const;
  
public:
  const TString& get(const char* chiave, const char* campo);
  const TRectype& get(const char* chiave);

  TRecord_cache(int num, int key = 1);
  TRecord_cache(const char* table, int key = 1);
  virtual ~TRecord_cache() { }
};

#endif

