#include <applicat.h>
#include <urldefid.h> 
#include <form.h>
#include <mask.h>   
#include <relation.h>
#include <printer.h>
#include <progind.h>
#include <lffiles.h>
#include <dos.h>
#include <errno.h>   
#include "ef0.h"   
#include "ef0301.h"
#include "ef0500.h"
#include "filetext.h"

class TRiba_form;
class TDistinta_form;
class TRiba_file;
enum fo{kb360 = 1, kb720 = 2, kb1200  = 3, kb1440  = 4};
///////////////////////////////////////////////////////////////////////
// Classe per l'emissione di effetti e distinte su carta o su floppy // 
///////////////////////////////////////////////////////////////////////
class TEmissione: public TApplication
{
  fo _foutput;
  TMask* _msk;
  TRelation* _firmrel;           
  TRelation* _rel;  
  TCursor* _cur;
  TRiba_form* _formrb;
  TDistinta_form* _formdse;
  TRiba_file* _trasfile;
  int _base_page_no;              
protected:
  virtual bool create(void);                        
  virtual bool destroy(void) ;                        
  virtual void on_firm_change(void); 
  virtual bool menu(MENU_TAG); 
  void conferma(void);               
  virtual void print_rb(char tipost, int ndist, char tipodist, int ncopie, const bool is_vis);                             
  virtual void print_dse(char tipost, int ndist, char tipodist, int ncopie, const bool is_vis); 
  virtual void print(void); 
  void floppy(void);               
  void save_data_emis(void);
  void header_rb(void);
  void footer_ef(void);
  void inizializza_cur(void); 
  void inizializza_file(void);                        
  void record(THash_object& lavoro);
  bool ok_write(void);   
  void aggiorna_rb(TCursor*);        
  void aggiorna_dist(TCursor*);      
  static bool annulla_handler(TMask_field& f, KEY k);  
public:                                              
  int base_no() { return _base_page_no;}
  const TMask& msk() const {return *_msk;}
  TEmissione() {};
  virtual ~TEmissione() {};
};

// restituisce un riferimento all' applicazione
inline TEmissione& app() { return (TEmissione&) main_app();}

/////////////////////////////////////////////////////////////
// Classe TRiba_form customizzata dalla Form per le Ri.Ba. // 
/////////////////////////////////////////////////////////////
class TRiba_form: public TForm
{ 
protected:  
  virtual bool validate(TForm_item &, TToken_string &); 
public:
  TRiba_form(const char *);
  virtual ~TRiba_form(){};
};

///////////////////////////////////////////////////////////////////
// Classe TDistinta_form customizzata dalla Form per le Distinte //
///////////////////////////////////////////////////////////////////
class TDistinta_form: public TForm
{ 
  TRelation *_firmrel;              
  TSorted_cursor *_cursor;// cursore che permette l'ordinamento degli effetti 
protected:                // nella distinta per data scadenza o per dati fattura
  virtual bool validate(TForm_item &, TToken_string &);   
public:
  void set_order(const char tipo); 
  virtual TCursor* cursor() const { return (TCursor*)_cursor;}
  TDistinta_form(const char*, TRelation *);
  virtual ~TDistinta_form();
};

/////////////////////////////////////////////////////
// Classe TRiba_file customizzata dalla TFile_text //
/////////////////////////////////////////////////////
class TRiba_file: public TFile_text
{ 
  long _nditta;                           
  real _tot_importi;
protected:  
  virtual void validate(TCursor& cur,TRecord_text &rec, TToken_string &val, TString& str);
public:
  TRiba_file(const TString& file_name, const TString& config_name):TFile_text(file_name, config_name){}
  virtual ~TRiba_file(){}                                                                                                                       
  void set_ditta(long nditta){_nditta = nditta;}
  const long ditta(void) const {return _nditta;}
  void set_tot_importi(real importo){_tot_importi = importo;}
  void add_tot_importi(real importo){_tot_importi += importo;}
  const real tot_importi(void) const {return _tot_importi;} 
};
                                
// creazione dell'applicazione
bool TEmissione::create()
{
  TApplication::create();            
  _formrb = NULL;                     
  _formdse = NULL;                     
  _msk = new TMask("ef0500a");  
  _firmrel= new TRelation(LF_NDITTE);
  _firmrel->add(LF_ANAG, "TIPOA=TIPOA|CODANAGR=CODANAGR");
  _firmrel->add(LF_UNLOC,"CODDITTA=CODDITTA");
  _rel = new TRelation(LF_EFFETTI);       
  _rel->add(LF_REFFETTI, "NPROGTR=NPROGTR");       
  _rel->add(LF_CESS, "NPROGTR=NPROGTR");
  _rel->add(LF_CLIFO, "TIPOCF=\"C\"|CODCF=CODCF"); 
  _rel->add("%BAN", "CODTAB[1,5]=CODABI", 1, 0, 401);   
  _rel->add("%BAN", "CODTAB=CODABI+CODCAB", 1, 0, 402);   
  _rel->add(LF_COMUNI, "STATO=STATOCF|COM=COMCF",1,LF_CLIFO);
  _cur = NULL;
  _trasfile = new TRiba_file("ribael.dat", "riba.ini");
  _trasfile->set_ditta(get_firm());
  _msk->set_handler(DLG_CANCEL, annulla_handler); 
  dispatch_e_menu(BAR_ITEM(1)); 
  return TRUE;
}

// distruzione dell'applicazione
bool TEmissione::destroy()
{                      
  if (_formrb) delete _formrb;
  if (_formdse) delete _formdse;      
  delete _msk;  
  delete _firmrel; 
  delete _rel; 
  delete _cur;            
  if ( _trasfile)
  {
      _trasfile->close();
      delete _trasfile;
  }
  return TApplication::destroy();
}

// carica la ditta corrente
void TEmissione::on_firm_change() 
{
  TLocalisamfile &firmfile= _firmrel->lfile();
  firmfile.put("CODDITTA", get_firm());
  _firmrel->read();
}

// carica la maschera per emissione effetti e  distinte 
bool  TEmissione::menu(MENU_TAG)
{
  KEY key = K_ENTER;                 
  while (key != K_QUIT)            
  {  
    key = _msk->run();               
    if (key == K_ENTER)           
      conferma();
  }
  return FALSE;
}                              

// gestisce la scelta fra le due possibili emissioni
void TEmissione::conferma()
{
  int tipoemis = _msk->get_int(F_TIPOEMIS);
  if (tipoemis == 1)               
     floppy();
  else
     print();                    
}  
  
// gestione emissione su floppy
void TEmissione::floppy()
{
     inizializza_cur(); 
     inizializza_file(); 
     long n_eff = _cur->items();
     bool condition = ok_write();
     if (!condition)       
        error_box("Impossibile continuare discetto pieno");
     else
     { 
           TProgind* pi;   
           pi = new TProgind(n_eff,"Emissione Ri.Ba. su floppy...",FALSE,TRUE,10);
           TAssoc_array& tracciati = _trasfile->tracciati();
           header_rb();//intestazione flusso effetti
           //scandisco tutti gli effetti della distinta selezionata
           for (*_cur = 0; _cur->pos() < n_eff; ++(*_cur))
           {
              pi->addstatus(1L);  
              save_data_emis();
              THash_object* lavoro =  tracciati.get_hashobj();
              //scandisco tutti i record  di un effetto
              for (int i = 0; lavoro != NULL; i++)
              {          
                record(*lavoro);//emetto il record
                lavoro =  tracciati.get_hashobj(); 
              }
           }                        
           footer_ef(); //chiusura flusso effetti 
           delete pi;
     }      
}       

// registro la data ed il numero di emissione dell'effetto corrente
void TEmissione::save_data_emis()
{       
   const TDate data_emis = _msk->get_date(F_DATAEMIS);
   TLocalisamfile& effetti = _rel->lfile();
   TEffetto effetto = effetti.curr();          
   long numero = effetto.numero();
   effetto.put(EFF_NUMEMISS, numero);
   effetto.put(EFF_DATAEMISS, data_emis);
   effetto.put(EFF_DATARIBA, data_emis);
   bool cond = TRUE;
   effetto.put(EFF_DISRIBAEST, cond);
   effetto.rewrite(effetti);
}

//emetto il record d'intestazione del flusso di effetti
void TEmissione::header_rb()
{
   TRecord_text rec;
   *_cur = 0;
   rec.set_type("RB");
   _trasfile->autoload(rec, *_cur);  
   _trasfile->write(rec); 
} 

//emetto il record di chiusura del flusso di effetti
void TEmissione::footer_ef()
{
    TRecord_text rec;
    *_cur = 0;
    rec.set_type("EF");
     _trasfile->autoload(rec, *_cur);  
     _trasfile->write(rec);
     _trasfile->write_file()->seekp(0, ios::end);
}

//inizializza il cursore per la gestione dei dati da caricare negli effetti
void TEmissione::inizializza_cur() 
{
     const int ndist = _msk->get_int(F_NUMBER);
     const char tipodist = _msk->get(F_TIPODIST)[0];
     TRectype from(_rel->lfile().curr()),
                    to(_rel->lfile().curr()); 
     from.zero();
     from.put(EFF_TIPODIST, tipodist);
     from.put(EFF_NDIST, ndist);  
     to = from;
     _cur = new TCursor(_rel,"",4,&from,&to);
     _cur->freeze();
}

//inizializza il file di testo su cui emettere gli effetti
void TEmissione::inizializza_file()                                 
{
   TString unita = _msk->get(F_UNITA);
   unita << ":\\" << _trasfile->name();
   TFilename file(unita);
   _trasfile->open(file,'w');
   _trasfile->set_tot_importi(0.0);
   _foutput = (fo)_msk->get_int(F_FOR_OUT);
}       

//emetto un record del flusso di effetti
void TEmissione::record(THash_object& lavoro)
{
   TString chiave = lavoro.key();
    if (chiave !="EF" && chiave !="RB")
    {
         TTracciato_record&  oggetto = (TTracciato_record&)lavoro.obj();
         const TString& tipo = oggetto.type();
         TRecord_text rec(tipo);
          //carico il record da emettere  
          _trasfile->autoload(rec, *_cur, &tipo);
          _trasfile->write(rec);//emetto i dati su file 
    }      
}

//controllo che ci sia spazio a sufficenza per emettere il flusso 
//sull'unità scelta dall'utente,ritorna TRUE se è possibile farlo
bool TEmissione::ok_write() 
{
  long elem = _cur->items();      
  int dim = _trasfile->recordsize();
  long nbyte = (elem*7+2)*dim;
  struct _diskfree_t  diskspace;
  char unita = _msk->get(F_UNITA)[0];
  unsigned drive;
  switch(unita)                                     
  {
    case 'a' :
                drive = 1;
                break;
    case 'b' :
                drive = 2;
                break;
  }
  // routine uses system call 0x36 to obtain information on the disk drive
  // specified by drive 
  _dos_getdiskfree(drive, &diskspace);
  unsigned long available_clusters = (unsigned long) diskspace.avail_clusters; 
  unsigned long sectors_per_cluster = (unsigned long) diskspace.sectors_per_cluster; 
  unsigned long bytes_per_sector = (unsigned long) diskspace.bytes_per_sector;
  unsigned long free_space = available_clusters * sectors_per_cluster * bytes_per_sector;
  switch (_foutput)
  {
   case kb360 :              
          return free_space + nbyte < 360000L;
          break;
   case kb720 : 
          return free_space + nbyte < 720000L;
          break;
   case kb1200 :
          return free_space + nbyte < 1200000L;
          break;
   case kb1440 :             
          return free_space + nbyte < 1440000L;
          break;                    
  }
  return TRUE;                    
}
  
// aggiorna numero e data di emissione ed il flag di stampa
// su tutti gli effetti nel cursore
void TEmissione::aggiorna_rb(TCursor* cur)  
{                           
  TLocalisamfile &eff = cur->file(LF_EFFETTI);
  for (*cur = 0; cur->pos() < cur->items(); ++(*cur))
  {  
     TEffetto effetto = eff.curr();          
     long numero = effetto.numero();
     effetto.put(EFF_NUMEMISS, numero);
     TDate data = _msk->get_date(F_DATAEMIS);
     effetto.put(EFF_DATAEMISS, data);
     bool cond = TRUE;
     effetto.put(EFF_EFFSTAMP, cond);  
     effetto.rewrite(eff);
  } 
}

// aggiorna il flag di stampa della distinta   
// su tutti gli effetti nel cursore
void TEmissione::aggiorna_dist(TCursor* cur)
{    
  TLocalisamfile &eff = cur->file(LF_EFFETTI);
  for (*cur = 0; cur->pos() < cur->items(); ++(*cur))
  {  
     TEffetto effetto = eff.curr();          
     bool cond = TRUE;
     effetto.put(EFF_DISTSTAM, cond);  
     effetto.rewrite(eff);
  } 
}

// gestione emissione su moduli cartacei delle riba
void TEmissione::print_rb(char tipost, int ndist, char tipodist, int ncopie, const bool is_vis)
{
  TCursor* fcur = _formrb->cursor();  
  TLocalisamfile &eff = fcur->file(LF_EFFETTI);                     
  TString16 filter;
  if (tipost == 'D')// se stampa definitiva effetti
    if (!_msk->get_bool(F_RIST))// se non deve ristampare le riba
       filter = "EFFSTAMP=\" \"";// setta il filtro del cursore per ...
  fcur->setfilter(filter,TRUE);// ... stampare solo gli effetti non ancora stampati
// setta la chiave 4 per il cursore per poter leggere tutti gli effetti della distinta
  fcur->setkey(4);
  TRectype darec(eff.curr());// fissa  i dati per la scelta degli ...
  darec.zero();// ... effetti nel primo e nell'ultimo record del cursore
  darec.put(EFF_NDIST, ndist);         
  darec.put(EFF_TIPODIST, tipodist);
  TRectype arec(darec);
  fcur->setregion(darec, arec);      
  long n = fcur->items();            
  fcur->freeze();                   
// se la stampa non si fa a video istanzia puntatore per la gestione 
// della barra di attesa 
  for (int j=0; j < ncopie; j++)
  {
    TProgind* pi;                       
    if (!is_vis)                      
      pi = new TProgind(n,"Stampa Effetti...",FALSE,TRUE,10);
    // ciclo sugli elementi del cursore di stampa
    for (*fcur = 0; fcur->pos() < n; ++(*fcur)) 
    {
      if (!is_vis)
      pi->addstatus(1L);   // aggiorna la barra d'attesa
      _formrb->print();    // stampa il form  
    } 
  }  
  if (tipost == 'D')  // se emetto riba in definitiva devo aggiornare  
    aggiorna_rb(fcur);// data, numero emissione e flag di stampa effetto
}

// gestione emissione su  moduli cartacei delle distinte
void TEmissione::print_dse(char tipost, int ndist, char tipodist, int ncopie, const bool is_vis)
{
  TCursor* fcur = _formdse->cursor();   
  TLocalisamfile &eff = fcur->file(LF_EFFETTI); 
// setta la chiave 4 per il cursore per poter leggere tutti gli effetti
// della distinta    
  TString16 filter;
  fcur->setfilter(filter,TRUE);       
  fcur->setkey(4);
  TRectype darec(eff.curr()); // fissa  i dati per la scelta degli ...
  darec.zero(); // ... effetti nel primo e nell'ultimo record del cursore
  darec.put(EFF_NDIST, ndist);         
  darec.put(EFF_TIPODIST, tipodist);
  TRectype arec(darec);
  fcur->setregion(darec, arec);
  long n = fcur->items();   
  fcur->freeze();        
// se la stampa non si fa a video istanzia puntatore per la gestione
// della barra di attesa 
  for (int j=0; j < ncopie; j++)
  {
    TProgind* pi;                       
    if (!is_vis)                      
      pi = new TProgind(n,"Stampa Distinta...",FALSE,TRUE,10);
    _base_page_no = 0; 
    if (!is_vis)
      pi->addstatus(1L); // aggiorna la barra d'attesa
    _formdse->print();   // stampa il form  
   // stampa numero di pagina (solo nella distinta) 
    _base_page_no = printer().getcurrentpage() -1;
  }
  if (tipost == 'D')  // se emetto distinta in definitiva ...
    aggiorna_dist(fcur);// ... devo aggiornare  flag di stampa distinta 
}                               

// gestione emissione  effetti/distinte su moduli cartacei
void TEmissione::print()
{
  int ncopie = _msk->get_int(F_NCOPIE);
  if (ncopie == 0) ncopie = 1;           
  printer().open();
  // TRUE se si stampa a video
  const bool is_vis = printer().printtype() == screenvis; 
  int emis = _msk->get_int(F_EMIS);
  int ndist = _msk->get_int(F_NUMBER);
  char tipodist = _msk->get(F_TIPODIST)[0];
  _rel->lfile().put(EFF_TIPODIST,tipodist);
 _rel->lfile().put(EFF_NDIST,ndist);   
  _rel->lfile().put(EFF_NRIGADIST,1);
  _rel->lfile().setkey(4);
  _rel->read();
  long codabi = _rel->lfile().get_long(EFF_CODABIP);     
  char tipost = _msk->get(F_TIPOST)[0];
  char tipord = _msk->get(F_TIPORD)[0];
// se emetto riba istanzio il form per le riba 
// se emetto distinta istanzio il form per le distinte  
  if (emis == 1)                   
  {                                  
    TString16 nomeform;
    nomeform.format("rb%05ld.frm",codabi);// compongo il nome del form
    if (!fexist(nomeform))                // ne controllo l'esistenza se non
       nomeform = "rb.frm";               // esiste utilizzo quello generico
    _formrb = new TRiba_form(nomeform);     
    print_rb(tipost,ndist,tipodist,ncopie,is_vis);
  }
  else                             
  {  
   TString16 nomeform;
    nomeform.format("dse%05ld.frm",codabi);// compongo il nome del form
    if (!fexist(nomeform))                 // ne controllo l'esistenza
       nomeform = "dse.frm";               // se non esiste utilizzo quello generico
    _formdse = new TDistinta_form(nomeform, _firmrel);
    _formdse->set_order(tipord);
    print_dse(tipost,ndist,tipodist,ncopie,is_vis);
  }
  printer().close();            
}

// handler per gestire la conferma dell'annullamento dei dati inseriti
// nella maschera       
bool TEmissione::annulla_handler(TMask_field& f, KEY k)
{ 
  TMask &m = f.mask(); 
  if (k == K_SPACE)
  {  
    if (yesno_box("Vuoi veramete annullare i dati inseriti"))
       m.reset(); 
  }       
  return TRUE;
}

// costruttore classe TRiba_form
TRiba_form::TRiba_form(const char* name): TForm()
{
  read(name);
}

// gestione dei messaggi estesi nei campi
bool TRiba_form::validate(TForm_item &cf, TToken_string &s)
{
  const TString code(s.get(0));      
  TString valore; 
   if (code == "_BANCAP")     
  {                                                      
  // gestione dei campi relativi alla banca di presentazione dell'effetto
  // sintassi: _BANCAP
    TCursor* cur = cursor(); 
    TRectype & ban = cur->curr(-204);
    valore.cut(0);
    valore << ban.get("S0");
    valore.trim();  
    ban = cur->curr(-202);             
    valore << " " << ban.get("S0");
    valore.trim(); 
    cf.set(valore);
    cf.put_paragraph(valore);
    cf.set("");
  }                              
  if (code == "_FATT")     
  {
  // gestione dei campi relativi alle/a fatture/a a cui si riferisce un effetto
  // sintassi: _FATT,<macro>
  // dove: <macro> è uno delle macro seguenti:
  //       "!A"         fattura o fatture
  //       "!DATI"      numero e data fattura 
  //       "!IMPFATT"   importo fattura
    TCursor* fcur = cursor(); 
    TLocalisamfile &eff = fcur->file(LF_EFFETTI);                  
    TEffetto effetto = eff.curr();
    long num = effetto.numero();
    bool condition = (effetto.fatt(num));//TRUE se effetto non raggruppato
    TToken_string* dati = effetto.dati_fatt(num);
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);         
  // "!A" se 1 sola fattura stampa 'a' altrimenti stampa 'e'
      if (in == "A") 
      {
        if (condition)
          cf.set("a");
        else           
          cf.set("e");
      }
  // "!DATIFATT" stampa numero e data fattura delle fatture a cui si riferisce l'effetto     
      if (in == "DATIFATT") 
      {
        int elem = dati->items();
        TString descfatt;
        for (int i = 0; i < elem; i+=3)
        {
            descfatt << dati->get(i);
            descfatt << "  ";         
            descfatt << dati->get(i+1);
            descfatt << "  ";
            cf.set(descfatt);
        }  
      }
  // "!IMPFATT" se 1 sola fattura ne stampa l' importo       
      if (in == "IMPFATT") 
      {
        if (condition)
        { 
          real importo(dati->get(2));
          cf.set(importo.string("###.###.###.###,@@"));
         } 
      }
    } 
    valore = cf.get();
    cf.put_paragraph(valore);
    cf.set(""); 
    return (TRUE);
  } 
  return TForm::validate(cf, s);
}

// costruttore classe TDistinta_form
TDistinta_form::TDistinta_form(const char* name, TRelation *rel): TForm(), _firmrel(rel)
{
  read(name);
  _cursor = NULL;
}

// setta l'ordinamento del TSordet_cursor del form 
void TDistinta_form::set_order(const char tipo)
{
  TString ordine;
  // ordinamento secondo la data di scadenza dell'effetto  
  if (tipo == 'S') 
     ordine  = "DATASCAD|TIPODIST|NDIST|NRIGADIST";
  // ordinamento seconda il numero e la data della fattura  
  if (tipo == 'F') 
     ordine = "14->NFATT|TIPODIST|NDIST|NRIGADIST";
  _cursor = new TSorted_cursor(relation(),ordine);
}

// distruttore classe TDistinta_form
TDistinta_form::~TDistinta_form()
{
  if (_cursor) delete _cursor;
}

// gestione dei messaggi estesi nei campi
bool TDistinta_form::validate(TForm_item &cf, TToken_string &s)
{
  const TString code(s.get(0));    
  TString valore;
   if (code == "_BANCAP")     
  {                             
  // gestione dei campi relativi alla banca di presentazione della distinta
  // sintassi: _BANCAP
    TCursor* cur = cursor(); 
    TRectype & ban = cur->curr(-204);
    valore.cut(0);
    valore << ban.get("S0");
    valore.trim();  
    ban = cur->curr(-202);             
    valore << " " << ban.get("S0");
    valore.trim(); 
    cf.set(valore);
    cf.put_paragraph(valore);
    cf.set("");
  }              
  if (code == "_DITTA")
  { 
  // gestione di campi della ditta corrente
  // sintassi: _DITTA,<macro>
  // dove: <macro> è uno delle macro seguenti:
  //       "!RAGSOC"     ragione sociale
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
  // "!RAGSOC" prende la ragione sociale della ditta corrente    
      if (in=="RAGSOC") 
      {
        const TString ragsoc = _firmrel->lfile().get("RAGSOC");
        valore.cut(0); 
        valore = ragsoc.left(30);
        valore.trim();      
        TString str = ragsoc.right(20);  
        str.trim();
        valore << " " << str;
        cf.set(valore);  
      }
    }
    valore = cf.get();
    cf.put_paragraph(valore);
    cf.set("");
    return (TRUE);
  } 
  if (code == "_FATT")
  { 
  // gestione dei campi relativi alle fatture a cui si riferisce un effetto
  // sintassi: _FATT,<macro>
  // dove: <macro> è uno delle macro seguenti:
  //       "!DATI"      numero e data fattura 
    TCursor* fcur = cursor(); 
    TLocalisamfile &eff = fcur->file(LF_EFFETTI);                  
    TEffetto effetto = eff.curr();
    long num = effetto.numero();
    TToken_string* dati = effetto.dati_fatt(num);
    int elem = dati->items();
    TString descfatt;
    TString in(s.get());  // prende il primo parametro, il codice del messaggio
    if (in[0]=='!')
    {
      in.ltrim(1);
  // "!DATIFATT"  stampa numero e data fattura delle fatture a cui si riferisce l'effetto           
      if (in == "DATIFATT") 
      {
        for (int i = 0; i < elem; i+=3)
        {
           descfatt << dati->get(i);
           descfatt << "  ";         
           descfatt << dati->get(i+1);
           descfatt << "  ";
           cf.set(descfatt);
        }  
      }
    }  
    valore = cf.get();
    cf.put_paragraph(valore);
    cf.set(""); // resetta il campo per la prossima stampa di questo item
    return (TRUE);
  } 
  if (code == "_FOOTER")
  { 
  // gestione dei campi del fondo pagina della distinta
  // sintassi: _FOOTER,<macro>
  // dove: <macro> è uno delle macro seguenti:
  //       "!NDOC"     numero riba nella distinta
  //       "!TOTALE"   totale presentato 
    TString in(s.get());             
    if (in[0]=='!')
    {
      in.ltrim(1);
      TCursor* fcur = cursor();
      long i = fcur->items(); 
  //"!NDOC" prende il numero riba nella distinta guardando quanti
  // elementi ha il cursore di  stampa     
      if (in == "NDOC")
        cf.set(format("%ld",i));
  //"!TOTALE" calcola il totale presentato prendendo i totale degli
  // effetti  nel cursore di  stampa           
      if (in == "TOTALE")
      {
        real totale = 0.0;        
        TLocalisamfile &eff = fcur->file(LF_EFFETTI);
        for (*fcur = 0; fcur->pos() < i; ++(*fcur))
        {  
          TEffetto effetto = eff.curr();
          real imp = (real)effetto.importo(); 
          totale +=imp;
        } 
        cf.set(totale.string("###.###.###.###,@@"));
      }
    }
    valore = cf.get();
    cf.put_paragraph(valore);
    cf.set(""); 
    return (TRUE);
  } 
  if (code== "_PAGENO")
  {  
  // messaggio per stampare il numero di pagina corrente
    TString16 pg; pg << int(printer().getcurrentpage() - app().base_no());
    cf.set(pg); cf.put_paragraph(pg);
    cf.set("");
  }
  return TForm::validate(cf, s);
}

// gestione dei messaggi estesi nei campi
void TRiba_file:: validate(TCursor& cur,TRecord_text &rec, TToken_string &s, TString& str)
{
  const TString code(s.get(0));      
  TString valore;                 
  if (code == "_FISSO")     
  {
   // gestione dei campi fissi per i record delle riba
   // sintassi: _FISSO,!<valore>
   // dove: <valore> è la stringa fissa da emettere 
    TString in(s.get());
     if (in[0]=='!')
    {
      in.ltrim(1); 
      in.trim();
      valore = in;
    }
  }       
  if (code == "_DATA")     
  {
   // gestione della data di emissione delle riba
   // sintassi: _DATA
     const TDate data_emis = app().msk().get_date(F_DATAEMIS);
     valore = data_emis.string();
  }
  if (code == "_NRIBA")     
  {
  // gestione dei campi relativi al flusso di effetti (riba)
  // sintassi: _NRIBA,<macro>
  // dove: <macro> è uno delle macro seguenti:
  //       "!NUM"     numero progressivo riba all'interno del flusso
  //       "!TOT"      numero di effetti nel flusso
  //       "!NREC"    numero di records nel flusso
    int items = (int)cur.items(); 
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      if (in=="NUM")
      {
        valore.cut(0);                
        valore << cur.pos() + 1; 
      } 
      if (in=="TOT")
      {
        valore.cut(0);                
        valore << items; 
      }                               
      if (in=="NREC")
      {
        valore.cut(0);
        int rec = items * 7 + 2;                
        valore << rec; 
      }
    }   
  }
  if (code == "_DITTA")     
  {  
    // gestione di campi della ditta corrente
   // sintassi: _DITTA,<macro>,<opzione>
   // dove: <macro> è uno delle macro seguenti:
   //       "!RAGSOC"     ragione sociale 
   // dove: <opzione> è uno delle opzioni seguenti:
   //      "0" la ragione sociale andrà ad occupare un unico campo
   //      "1" la ragione sociale andrà ad occupare più campi, primo segmento
   //      "2" la ragione sociale andrà ad occupare più campi, secondo segmento
   //      "3" la ragione sociale andrà ad occupare più campi, terzo segmento
   //      "4" la ragione sociale andrà ad occupare più campi, quarto segmento
    TLocalisamfile ditte(LF_NDITTE); 
    ditte.put("CODDITTA",ditta());
    ditte.read();
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      if (in=="RAGSOC")
      {
        const TString ragsoc = ditte.get("RAGSOC");
        in = s.get();
        if (in == "0") 
        {
          valore.cut(0); 
          valore = ragsoc.left(30);
          valore.trim();      
          TString str = ragsoc.right(20);  
          str.trim();
          valore << " " << str;
        }
        else
        {                      
            TParagraph_string string(ragsoc,24);
            string.restart();
            int indice = atoi(in);
            if (in == "1") valore = string.get(indice-1); 
            if (in == "2") valore = string.get(indice-1);
            if (in == "3") valore = string.get(indice-1);
            if (in == "4") valore = string.get(indice-1);
        }
      } 
    }
  }
  if (code == "_DEBITORE")     
  { 
  // gestione di campi della ditta corrente
   // sintassi: _DEBITORE,<macro>,<opzione>
   // dove: <macro> è uno delle macro seguenti:
   //       "!RAGSOC"     ragione sociale
   //       "!INDIRIZZO" indirizzo 
   //       "!PIAZZA"      comune + sigla provincia
   // dove: <opzione> è uno delle opzioni seguenti:
   //      "1" la ragione sociale andrà ad occupare più campi, primo segmento
   //      "2" la ragione sociale andrà ad occupare più campi, secondo segmento
    TRectype& clifo = cur.curr(LF_CLIFO);
    TRectype& comuni = cur.curr(LF_COMUNI);
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      if (in=="RAGSOC")
      {
        TString ragsoc = clifo.get("RAGSOC");
        in = s.get();
        TParagraph_string string(ragsoc,30);
        string.restart();
        int indice = atoi(in);
        if (in == "1") valore = string.get(indice-1); 
        if (in == "2") valore = string.get(indice-1);
      }    
      if (in=="INDIRIZZO")
      {
        valore.cut(0);
        valore << clifo.get("INDCF");   
        valore.trim();                           
        valore << " " << clifo.get_int("CIVCF");
        valore.trim();    
        valore << " " << clifo.get("LOCALITACF");
        valore.trim();   
      }
      if (in=="PIAZZA")
      {
        valore.cut(0);
        valore << comuni.get("DENCOM");
        valore.trim();
        valore << " " << comuni.get("PROVCOM");  
        valore.trim();
      }  
    } 
  }                                    
  if (code == "_BANCA")     
  { 
  // gestione dei campi relativi alla banca d'appoggio dell'effetto
  // sintassi: _BANCA
    TRectype & ban = cur.curr(-401);
    valore.cut(0);
    valore << ban.get("S0");
    valore.trim();  
    ban = cur.curr(-402);             
    valore << " " << ban.get("S0");
    valore.trim();
  }                               
  if (code == "_FATT")     
  { 
  // gestione dei campi relativi alle/a fatture/a a cui si riferisce un effetto
  // sintassi: _FATT,<opzione>
  // dove: <opzione> è uno delle opzioni seguenti:
  //  "1" i dati della fattura andranno ad occupare più campi, primo segmento
  //  "2" i dati della fattura andranno ad occupare più campi, secondo segmento
    TLocalisamfile &eff = cur.file();                  
    TEffetto effetto = eff.curr();
    long num = effetto.numero();
    TToken_string* dati = effetto.dati_fatt(num);
    int elem = dati->items();
    TString descfatt;
    for (int i = 0; i < elem; i+=3)
    {
           descfatt << dati->get(i);
           descfatt << " ";         
           descfatt << dati->get(i+1);
           descfatt << " ";
    }                                    
    int l = descfatt.len();
    TString in(s.get());  
    if (in[0]=='!')
    {
      in.ltrim(1);
      if (in == "1") 
      {
       valore = descfatt.left(40);
       valore.trim();
      }
      if (in == "2") 
      {
       valore = descfatt.mid(40, l);
      }
    }  
  }
  if (code == "_IMPORTO")     
  {
  // gestione di campi degli importi degli effetti nel flusso
   // sintassi: _IMPORTO,<macro>
   // dove: <macro> è uno delle macro seguenti:
   //       "!ADD" aggiunge l'importo dell'effetto corrente al totale    
   //       "!TOT" emette il totale
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      if (in=="ADD")
      {
        real importo(str);                  
        add_tot_importi(importo);
        valore.cut(0);
        valore << importo.string(13,1);
      }
      if (in=="TOT")
      {
        valore.cut(0);  
        real importo = tot_importi();  
        valore << importo.string("############@,@");               
        set_tot_importi(0.0);
      }
    }
  }
  str = valore;   
} 

int ef0500(int argc, char* argv[])
{
  TEmissione a ;
  a.run(argc, argv, "Emissione Effetti e Distinte");
  return 0;
}