#ifndef __FILETEXT_H
#define __FILETEXT_H

#ifndef __ARRAY_H
#include <array.h>
#endif 
#ifndef __CONFIG_H
#include <config.h>    
#endif 
#ifndef __CHECS_H
#include <checks.h> 
#endif 
#ifndef __ASSOC_H
#include <assoc.h>
#endif 
#ifndef __RELATION_H
#include <relation.h>
#endif 
#include <utility.h>  
#include <fstream.h>       

///////////////////////////TTracciato_Campo////////////////////////////////
// Classe per la definizione delle specifiche riguardanti un campo di un //
// record di un file di testo                                            //
///////////////////////////////////////////////////////////////////////////
class TTracciato_campo : public TObject                 
{
  TString _name;//descrizione del contenuto  
  TString _type;//tipo predefinito       
  TFieldref _field;//nome su file/relazione 
  int _position;//posizione su file di testo   
  int _length;//lunghezza   
  int _decimal;//numero di decimali   
  char _align;//allineamento   
  char _filler;//carattere di riempimento   
  TString _picture;//formato   
  TToken_string _message;//messaggio per gestire personalizzazione del campo
protected:
  void copy(const TTracciato_campo& tc);//copia membro a membro
public:                                         
  TTracciato_campo(int position = -1, int length = -1, int decimal = -1, const char align = 'R', const char filler = ' '); 
  TTracciato_campo(const TTracciato_campo& tc){copy(tc);}
  virtual ~TTracciato_campo() {}
  virtual TObject* dup() const;
  const TTracciato_campo& operator =(const TTracciato_campo& tc);
  const TString& name() const {return _name;}
  const TString& type() const {return _type;}     
  const TFieldref& field() const {return _field;}
  const int position() const {return _position;}
  const int length() const {return _length;}
  const int decimal() const {return _decimal;}
  const char align() const {return _align;}
  const char filler() const {return _filler;}
  const TString& picture() const {return _picture;} 
  const TString& message() const {return _message;} 
  void set_name(const TString& name) {_name = name;}
  void set_type(const TString& type) {_type = type;}   
  void set_field(const TFieldref& field) {_field = field;} 
  void set_position(const int position) {_position = position;}
  void set_length(const int length) {_length = length;}
  void set_decimal(const int decimal) {_decimal = decimal;} 
  void set_align(const char align) {_align = toupper(align);}
  void set_filler(const char filler ) {_filler = filler;}
  void set_picture(const TString& picture ) {_picture = picture;} 
  void set_message(const TString& message ) {_message = message;}
};
/////////////////////////// TTracciato_record /////////////////////////
// Classe per la definizione delle specifiche riguardanti un record  //
// come insieme di più campi                                         //
///////////////////////////////////////////////////////////////////////
class TTracciato_record : public TObject
{
  TString _type;//tipo del record
  TArray _tracciati_campo;//tracciati dei vari campi  
public:                               
  TTracciato_record(const TString& tipo) : _type(tipo) {}               
  TTracciato_record(const  TTracciato_record& tr);
  virtual  ~TTracciato_record() {}
  virtual TObject* dup() const;
  TArray& tracciati_campo() { return _tracciati_campo;}//ritorna un riferimento all'array dei tracciati campo
  const TString& type() const {return _type;}
  void set_type(const TString& type) {_type = type;}                                                        
  void add(const TTracciato_campo& tc, int pos = -1);//aggiunge tracciato campo all'array 
  TTracciato_campo& get(int n);//ritorna il tracciato campo n dell'array (se non c'e' lo crea)     
  //ritorna il tracciato campo n dell'array 
  const TTracciato_campo& get(int n) const {return (TTracciato_campo&)_tracciati_campo[n];}
  //ritorna il puntatore al tracciato campo n dell'array (NULL se non esiste)
  TTracciato_campo* ptr(int n) {return (TTracciato_campo*)_tracciati_campo.objptr(n);}
};
///////////////////////////// TRecord_text /////////////////////////////////
// Classe per la definizione di un record di un File_text, consiste di un //
// array che contiene tutti i valori dei campi risultanti dal tracciato   //
// record                                                                 //
////////////////////////////////////////////////////////////////////////////                       
class TRecord_text : public TObject
{                                                          
  TString _type;//tipo del record
  TString_array _array;//array che contiene i valori dei campi 
public:
  TRecord_text() {}
  TRecord_text(const TString& type):   _type(type) {}
  virtual ~TRecord_text(){}
  const TString& type() const {return _type;} 
  void set_type(const TString& type) {_type = type;} 
  const TString& row(int pos) const;//ritorna il campo dell'array della posizione <pos>     
  void add(const TString& c, int pos = -1);//scrive il campo <c> nell'array  alla posizione <pos> 
  const int items() const {return _array.items();}//ritorna il numero di elementi dell'array
  virtual bool destroy(int index = -1, bool pack = FALSE) {return _array.destroy(index, pack);}
};
///////////////////////////////// TFile_text //////////////////////////////////////
// Classe per la definizione di un file di testo  capace di leggersi e scriversi,//
// in base ai tracciati record e campo risultanti; utilizzabile per trasferimenti//
// (ricezioni ed invii) di file o di relazioni                                   //
///////////////////////////////////////////////////////////////////////////////////          
class TFile_text : public TObject
{ 
  ifstream* _read_file;//stream per lettura da file di testo
  ofstream* _write_file;//stream per scrittura su file di testo
  TFilename _name;//nome del file di testo
  TRecord_text* _current;//puntatore al record_text corrente
  TAssoc_array _tipi;//tracciati campo per i vari tipi predefiniti 
  TAssoc_array _tracciati_record;//tracciati record per i vari tipi di record 
  char _decsep;//separatore decimale 
  int _recordsize;//dimensione dei record 
  char _fieldsep;//separatore di campo (se a lunghezza variabile)
  TString _recordsep;//separatore di record  (se a lunghezza variabile)                     
  bool _fixedlen;//booleano TRUE lunghezza fissa FALSE lunghezza variabile
  int _typepos;//posizione ove trovare la chiave nel record a lunghezza fissa
  int _typelen;//lunghezza della chiave del record a lunghezza fissa 
  int _typefield;//posizione ove trovare la chiave nel record a lunghezza variabile
protected:
  //effettua operazioni personalizzate dall'applicazione sul record_text
  // <cur> è il cursore della relazione 
  // <rec> è il record da modificare
  // <val> contiene il messaggio da modificare e/o caircare nel record
  // <str> conterrà il risultato dell'operazione
  virtual void validate(TCursor& cur, TRecord_text &rec, TToken_string &val, TString& str){} 
public:        
  TFile_text(const TString& file_name, const TString& config_name);
  virtual ~TFile_text(){}
  ifstream* read_file() {return _read_file;}
  ofstream* write_file() {return _write_file;}
  void set_gen_parm(TConfig& config, TString& section);//scarica i parametri generali dal file di configurazione   
  //scarica i parametri relativi ai vari tipi predefiniti dal file di configurazione
  void set_type_parm(TConfig& config, TString& section);
  //scarica i parametri relativi ai vari tipi di record dal file di configurazione   
  void set_rec_parm(TConfig& config, TString& section);                           
  int open(TFilename name, char mode);//apertura del file di testo (mode = r|w)
  int close();//chiusura del file di testo
  inline const int ok_r() {return _read_file->good();}//ritorna lo stato del file di lettura
  inline const int ok_w() {return _write_file->good();}//ritorna lo stato del file di scrittura
  const TString& name() const {return _name;}//ritorna il nome del file
  void set_name(const TFilename name) {_name = name;}//setta il nome del file
  const char decsep() const {return _decsep;}
  const int recordsize() const {return _recordsize;}
  const char  fieldsep() const {return _fieldsep;}
  const TString&  recordsep() const {return _recordsep;}               
  const bool fixedlen() const {return _fixedlen;}
  const int typepos() const {return _typepos;}
  const int typelen() const {return _typelen;}
  const int typefield() const {return _typefield;}
  const TRecord_text& curr() const {return *_current;}//ritorna il record corrente
  void set_curr(TRecord_text& rec) {_current = &rec;}//setta il record corrente a rec 
  void set_curr(TRecord_text* rec) {_current = rec;}//setta il record corrente a rec     
  TTracciato_record& t_rec(const TString& type);//ritorna il tracciato record del tipo passato
  const int items_tr() const {return _tracciati_record.items();}//ritorna il numero di tracciati record nel file 
  TAssoc_array& tracciati() {return _tracciati_record;}//ritorna un riferimento all'assoc_array dei tracciati record
  //caricamento automatico del record_text dalla relazione 
  void autoload(TRecord_text& rec, TCursor& cur,  const TString* tipo = NULL); 
  //caricamento automatico del record_text corrente dalla relazione l
  void autoload(TCursor& cur,  const TString* tipo = NULL) {autoload(*_current, cur, tipo); }; 
  int write(TRecord_text & rec);//scrive su file di testo il record 
  int write(){return write(*_current);}//scrive su file di testo il record_text corrente    
  //caricamento automatico della relazione dal record_text 
  int autosave(TRelation& rel, const TRecord_text& rec); 
  //caricamento automatico della relazione dal record_text corrente
  int autosave(TRelation& rel) {return autosave(rel, *_current); }; 
  int read(TRecord_text & rec);//legge da  file di testo il record_text 
  int read(){return read(*_current);}//legge da file di testo il record_text corrente
  //carica nel record_text il campo alla posizione <ncampo> con il valore <val> già formattato
  void add_field(TRecord_text& rec, const int ncampo, const char* val);
  //scarica dal record_text il campo alla posizione <ncampo>
  const TString& get_field(TRecord_text& rec, int ncampo);
  void format_date(const TDate& data, const TString& form, TString& data_str);//formatta la data
  TString& format_field(TTracciato_campo& tc, TString& campo);//formatta il campo secondo il  suo tracciato
};                  

#endif //__FILETEXT_H