#ifndef __MULTIREC_H
#define __MULTIREC_H

#ifndef __RECARRAY_H
#include <recarray.h>
#endif

#ifndef __VARREC_H
#include <varrec.h>
#endif

//**************************************
// classe per il controllo dei record composti da una testata e N file di righe
// è implementato come un TRectype che contiene anche un TRecord_array
//
class TMultiple_rectype : public TAuto_variable_rectype
{
  // @cmember Array di TRecord array per le righe
  TArray _files;  //
  // @cmember flag indicatore  di record nuovo
  bool _nuovo;
  // @cmember file delle righe
  TPointer_array _logicnums;
  // @cmember Indicazione di record array non più corrispondente alla testata
  TBit_array _changed;
  // @cmember Indicazione autoload
  TBit_array _autoload;
  // @cmember Array di nomi di campo "numeratore" delle righe
  TString_array _numfields;

  int lognum(int index) const { return _logicnums.get_int(index); }

protected:
  const TArray & files() const { return _files;}
  // @cmember Documento nuovo (non presente sul database).
  bool nuovo() const { return _nuovo; }
  // @cmember funzione per costruire la chiave delle righe
  virtual void set_body_key(TRectype & rowrec); 
  // @cmember verifica se la chiave della testata e' completa
  virtual bool key_complete() const;
  // @cmember setta la chiave della testata ad un valore nuovo (next-key)
  virtual bool renum();
  // @cmember renumera le chiavi di tutti i corpi in base alla testata
  virtual void renum_key();
  // @cmember Genera il record del corpo
  virtual TRectype * new_body_record(int logicnum = 0) { return new TRectype(logicnum ? logicnum : lognum(0)); }
  // @cmember Crea e carica il record array del corpo
  virtual void load_rows_file(int logicnum);
  // @cmember Ritorna l'indice di <p _files> del numero logico passato
  int log2ind(int logicnum) const;
  // @cmember Ricerca la prima occorrenza del corpo con fieldname uguale a s
  virtual int find(int logicnum, const char * fieldname, const char * s, int from = 0, bool reverse = FALSE) const ;
  // @cmember Scrive/riscrive un corpo
  virtual int write_rewrite(TBaseisamfile& f, bool re = FALSE) const;
  // @cmember Rimuove un corpo
  void remove_body(int logicnum);

  // @cmember Associa un file a quello principale
  void add_file(int logicnum, const char * numfield);
  // @cmember sincronizza tutti i body (li legge, se necessario) in seguito ad una lettura della testata
  virtual void synchronize_bodies();
  virtual TMultiple_rectype & copy(const TMultiple_rectype & r);
  virtual TObject* dup() const { return new TMultiple_rectype(*this); }

  // @cmember restituisce il numero di record attualmente caricati nel corpo (da usare nella dirty fields)
  int loaded_rows(int logicnum = 0) const;
  // @cmember confronta due record multipli
  virtual int compare(const TSortable& s) const;

public:
  //***********************
  // struttura
  // @cmember restituisce il record di testata
  const TAuto_variable_rectype& head() const { return *this; } // Ritorna la testata del documento
  // @cmember restituisce il record di testata
  TAuto_variable_rectype& head() { return *this; } // Ritorna la testata del documento

  // @cmember restituisce il record array del corpo
  virtual TRecord_array & body(int logicnum = 0) const;
  // @cmember restituisce il numero di record nel corpo
  int rows(int logicnum = 0) const { return body(logicnum).rows(); }

   // @cmember restituisce il record n-esimo del del corpo
  const TRecord_array & operator[](int logicnum) const { return (const TRecord_array &)((TMultiple_rectype *)this)->body(logicnum); }
  // @cmember restituisce il record n-esimo del del corpo
  TRecord_array & operator[](int logicnum) { return (TRecord_array &)body(logicnum); }

  // @cmember distrugge una riga del record array del corpo
  bool destroy_row(int n, bool pack = FALSE, int logicnum = 0) { return body(logicnum).destroy_row(n, pack); }
  // @cmember distrugge tutte le righe del record array del corpo
  void destroy_rows(int logicnum = 0) { body(logicnum).destroy_rows(); }

  // @cmember inserisce una riga alla posizione <par row> nel record array del corpo <par logicnum>
  TRectype & insert_row(int row, int logicnum = 0);
  // @cmember inserisce una riga alla posizione <par row> nel record array del corpo <par logicnum>
  TRectype & new_row(int logicnum = 0);

  // @cmember Abilita il caricamento del corpo <par lognum> insieme alla testata
  void enable_autoload(int lognum = 0 ,bool on =TRUE);
  // @cmember Restituisce il flag di caricamento del corpo <par lognum> insieme alla testata
  bool autoload_enabled(int lognum =0 );

  //***********************
  // record e I/O
  virtual void dirty_fields() {}
  virtual void set_fields(TAuto_variable_rectype & rec) {}
  virtual void reset_fields(TAuto_variable_rectype & rec) { rec.remove_field(); }

  virtual TMultiple_rectype & operator =(const TMultiple_rectype & r) { return copy(r);}
  virtual TRectype & operator =(const TRectype & r);
  virtual TRectype & operator =(const char * r);
  virtual void zero(char c = '\0');

  virtual int read(const TRectype & rec, word op = _isequal, word lockop = _nolock) {TLocalisamfile f(num()); *this = rec; return read(f, op, lockop); }
  virtual int read(word op = _isequal, word lockop = _nolock) { TLocalisamfile f(num()); return read(f, op, lockop); }
  // @cmember Legge il file <p f> con il tipo di record alla posizione desiderata
  virtual int readat(TBaseisamfile& f, TRecnotype nrec, word lockop = _nolock);
  virtual int read(TBaseisamfile & f, word op = _isequal, word lockop = _nolock);

  virtual int write(TBaseisamfile& f) const { return write_rewrite(f);}
  virtual int rewrite(TBaseisamfile& f) const { return write_rewrite(f, TRUE);}
  virtual int remove(TBaseisamfile& f) const;

  virtual int remove() const { TLocalisamfile f(num()); return remove(f);}
  virtual int write() const { TLocalisamfile f(num()); return write(f);}
  virtual int rewrite() const { TLocalisamfile f(num()); return rewrite(f);}

  virtual void fill_transaction(TConfig& cfg, int row = 0) const;
  
  bool is_equal(const TMultiple_rectype& r) const;
  
  //**************************
  // @cmember costruttore dal numero del file
  TMultiple_rectype(int hfn);
  // @cmember costruttore dal file
  TMultiple_rectype(const TBaseisamfile* file);
  // @cmember costruttore dal record
  TMultiple_rectype(const TRectype & rec);
  // @cmember costruttore di copia
  TMultiple_rectype(const TMultiple_rectype& r);
  virtual ~TMultiple_rectype() {}
};

#endif