#include <applicat.h>
#include <filetext.h>
#include <form.h>
#include <mask.h>
#include <printer.h>
#include <progind.h>

#include "ef0.h"
#include "ef0301.h"
#include "ef0500.h"
#include "../ve/velib.h"

#include <clifo.h>
#include <comuni.h>
#include <cfven.h>
#include <indsp.h>

class TRiba_form;
class TDistinta_form;
class TRiba_file;

#define RIBAFILENAME "ribael.dat"

///////////////////////////////////////////////////////////////////////
// Classe per l'emissione di effetti e distinte su carta o su floppy //
///////////////////////////////////////////////////////////////////////

class TEmissione: public TSkeleton_application
{
  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 void main_loop();
  virtual bool destroy(void) ;
  virtual void on_firm_change(void);
  void conferma(void);              
  void enable_dettaglio(TForm& form) const;
  virtual void print_rb(char tipost, int ndist, char tipodist, const bool is_vis);
  virtual void print_dse(char tipost, int ndist, char tipodist, 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*);
  bool test_record_type(const TString& key) const;

public:
  int base_no() const { return _base_page_no; }
  const TMask& msk() const { return *_msk; }
  const TRelation& firm_rel() const { return *_firmrel; }
  
  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
{
  real _tot_importi;
  char _codice_moneta;
  bool _tracciato_setif, _iban_pag, _iban_inc;
  TString _my_iban;  // IBAN del mio conto corrente (ordinante)
  
protected:
  virtual void validate(TCursor& cur,TRecord_text &rec, TToken_string &val, TString& str);

public:
  void set_tot_importi(const real& importo) { _tot_importi = importo; }
  void add_tot_importi(const real& importo) { _tot_importi += importo; }
  const real tot_importi() const { return _tot_importi; }
  
  bool tracciato_setif() const { return _tracciato_setif; }
  void set_tracciato_setif(bool tracciato_setif=TRUE) { _tracciato_setif = tracciato_setif; }
  
  const TString& my_iban() const { return _my_iban; }
  void set_my_iban(const char* ib) { _my_iban = ib; }
  bool iban_pag() const { return _iban_pag; }
  bool iban_inc() const { return _iban_inc; }
  void set_iban_pag(bool ib) { _iban_pag = ib; }
  void set_iban_inc(bool ib) { _iban_inc = ib; }

  TRiba_file(const TString& file_name, const TString& config_name);
  virtual ~TRiba_file() { }
};

TRiba_file::TRiba_file(const TString& file_name, const TString& config_name)
          : TFile_text(file_name, config_name)
{
  _codice_moneta = TCurrency::get_firm_dec() == 0 ? ' ' : 'E';
}

// creazione dell'applicazione
bool TEmissione::create()
{
  _formrb = NULL;
  _formdse = NULL;
  _msk = new TMask("ef0500a");
  _msk->set(F_NOMEFILE,RIBAFILENAME);
  _msk->set(F_PATH, "A:\\");
  
  _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==TIPOCF|CODCF==CODCF");
  _rel->add(LF_CFVEN, "TIPOCF==TIPOCF|CODCF==CODCF", 1, LF_CLIFO);
  _rel->add(LF_INDSP, "TIPOCF==TIPOCF|CODCF==CODCF|CODIND==CODINDEFF", 1, LF_CFVEN);
  _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);
  _rel->add(LF_COMUNI, "STATO==STATO|COM==COM", 1, LF_INDSP, 213);
  _rel->add("BNP", "CODTAB=CODABIP+CODCABP", 1, 0, 403);
  _rel->add(LF_DOC, "PROVV==PROVV|ANNO==ANNODOC|CODNUM==CODNUM|NDOC==NFATT", 1, LF_REFFETTI);
	_rel->lfile(LF_DOC).set_curr(new TDocumento);

  _cur = NULL;
  _trasfile = NULL;
  return TSkeleton_application::create();
}

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

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

// carica la maschera per emissione effetti e  distinte
void TEmissione::main_loop()
{ 
  // Preimposta gli eventuali valori specificati sulla riga di comando            
  if (argc() >= 4)    
  {
    TLocalisamfile eff(LF_EFFETTI);
    eff.setkey(4);
    eff.put(EFF_TIPODIST, argv(2));
    eff.put(EFF_NDIST, argv(3));
    eff.put(EFF_NRIGADIST, 1);
    if (eff.read() == NOERR)       
    {
      _msk->set(F_TIPODIST, eff.get(EFF_TIPODIST));
      _msk->set(F_TIPOCF, eff.get(EFF_TIPOCF));
      _msk->set(F_NUMBER, eff.get(EFF_NDIST));
    }
  }
  
  KEY key = K_ENTER;
  while (key != K_QUIT)
  {
    key = _msk->run();
    if (key == K_ENTER)
      conferma();
  }
}

// gestisce la scelta fra le due possibili emissioni
void TEmissione::conferma()
{
  const int tipoemis = _msk->get_int(F_TIPOEMIS);
  if (tipoemis == 1)
    floppy();
  else
    print();
}

// gestione emissione su floppy
void TEmissione::floppy()
{
  inizializza_cur();
  
  *_cur = 0L;  // Posizionati all'inizio
  const TRectype& eff = _cur->curr();
  const long codabi  = eff.get_long(EFF_CODABIP);
  const char tipocf  = eff.get_char(EFF_TIPOCF);
  const char tipopag = eff.get_char(EFF_TIPOPAG);
  
  TFilename ribaini;
  ribaini.format("r%c%c%05ld.ini", tipocf, tipopag, codabi); // compongo il nome del tracciato
  if (!ribaini.exist())              // se non esiste
    ribaini.overwrite("00000", 3);   // Elimino codice banca
  if (!ribaini.exist())              // se non esiste
    ribaini.overwrite("0", 2);       // Elimino tipo pagamaneto
  if (!ribaini.exist())              // se non esiste
    ribaini = "riba.ini";            // utilizzo quello generico
  if (!ribaini.custom_path())        // se non esiste ancora!
  {
    error_box(FR("Impossibile leggere il file %s"), (const char*)ribaini);
    return;
  }
             
  _trasfile = new TRiba_file(RIBAFILENAME, ribaini);
  TTracciato_record * rb = _trasfile->t_rec("RB");
  if (rb != NULL)
  {                    
    TTracciato_record * ib = new TTracciato_record(*rb);  
    ib->set_type("IB");
    _trasfile->tracciati().add("IB", ib);
  }
  inizializza_file();
  
  const bool condition = ok_write();
  
  if (!condition)
    error_box(TR("Impossibile scrivere sull'unita' di destinazione"));
  else
  {
    const TRecnotype n_eff = _cur->items();
    if (n_eff > 0)
    {
      TProgind pi(n_eff,TR("Emissione Ri.Ba. su file..."),FALSE,TRUE);
      
      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
    }
    message_box("Effetti emessi: %d", n_eff);
  }
  _trasfile->close();
  delete _trasfile;
  _trasfile = NULL;
  
  delete _cur;
  _cur = NULL;
}

// 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()
{
  *_cur = 0;
  const TRectype& eff = _rel->curr();

  TString16 codtab = eff.get(EFF_CODABIP);
  codtab << eff.get(EFF_CODCABP);
 
  const TRectype& bnp = cache().get("BNP", codtab);
  const bool setif = bnp.get_bool("B0");
  _trasfile->set_tracciato_setif(setif);

  _trasfile->set_my_iban(bnp.get("S3"));
  _trasfile->set_iban_pag(bnp.get_bool("B1"));
  _trasfile->set_iban_inc(bnp.get_bool("B2"));

  TRecord_text rec(setif ? "RB" : "IB");
  _trasfile->autoload(rec, *_cur); 
  _trasfile->write(rec);
}

//emetto il record di chiusura del flusso di effetti
void TEmissione::footer_ef()
{
  *_cur = 0;
  if (!_trasfile->tracciato_setif())
  {
    TTracciato_record* trec = _trasfile->t_rec("EF");
    const int p1 = trec->get(7).position();
    const int p2 = trec->get(8).position();

    trec->get(7).set_position(p2);
    trec->get(8).set_position(p1);
  }
  TRecord_text rec("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->curr());
  from.zero();
  from.put(EFF_TIPODIST, tipodist);
  from.put(EFF_NDIST, ndist);
  if (_cur != NULL)
    delete _cur;
  _cur = new TCursor(_rel,"",4,&from,&from);
  _cur->freeze();
}

//inizializza il file di testo su cui emettere gli effetti
void TEmissione::inizializza_file()
{
   TFilename fileriba = _msk->get(F_PATH);
   fileriba.add(_msk->get(F_NOMEFILE));
	 fileriba.fremove();
   _trasfile->open(fileriba,'w');
   _trasfile->set_tot_importi(ZERO);
   _trasfile->force_record_separator(_msk->get_bool(F_FORCESEP));
}

bool TEmissione::test_record_type(const TString& key) const
{
  bool ok = true;
  if (key == "16" || key == "17")
  {
    const TRectype& eff = _cur->curr();

    if (key == "16")
      ok = _trasfile->my_iban().not_empty();
    else
      ok = eff.get(EFF_IBAN).not_empty();

    if (ok)
    {
      const char tipocf = eff.get_char(EFF_TIPOCF);
      if (tipocf == 'C')
        ok = _trasfile->iban_inc();
      else
        ok = _trasfile->iban_pag();
    }
  }
  return ok;
}

//emetto un record del flusso di effetti
void TEmissione::record(THash_object& lavoro)
{
  const TString& chiave = lavoro.key();
  if (chiave !="EF" && chiave !="RB" && chiave != "IB")
  {
    const TTracciato_record& oggetto = (TTracciato_record&)lavoro.obj();
    const TString& tipo = oggetto.type();
    if (test_record_type(tipo))
    {
      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();
  unsigned long nbyte = (elem*7+2)*dim;

  const TString& unita = _msk->get(F_PATH);
  return xvt_fsys_test_disk_free_space(unita, nbyte) != 0;
}

// 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, const bool is_vis)
{
  TCursor* fcur = _formrb->cursor();
  TLocalisamfile &eff = fcur->file(LF_EFFETTI);
  
  TString filter;
  if (tipost == 'D' && !_msk->get_bool(F_RIST))  // se stampa definitiva effetti e se non deve ristampare le riba
    filter = "EFFSTAMP=\" \"";// setta il filtro del cursore per 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);
  if (ndist > 0)
  {
    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_TIPODIST, tipodist);
    darec.put(EFF_NDIST, ndist);
    fcur->setregion(darec, darec);
  }
  else
  {
    if (filter.not_empty()) filter << "&&";
    filter << "(TIPODIST==\"\")&&(NDIST==\"\")";
  }
  fcur->setfilter(filter,TRUE);
  
  _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, const bool is_vis)
{
  TCursor* fcur = _formdse->cursor();
// setta la chiave 4 per il cursore per poter leggere tutti gli effetti
// della distinta
  TString16 filter;
  if (tipost == 'D' && !_msk->get_bool(F_RIST))  // se stampa definitiva effetti e se non deve ristampare le riba
    filter = "DISTSTAM=\" \"";// setta il filtro del cursore per ...
  fcur->setfilter(filter,TRUE);
  fcur->setkey(4);
  TRectype darec(LF_EFFETTI); // fissa  i dati per la scelta degli ...
                              // ... effetti nel primo e nell'ultimo record del cursore
  if (ndist > 0)
  {
    darec.put(EFF_NDIST, ndist);
    darec.put(EFF_TIPODIST, tipodist);
    fcur->setregion(darec, darec);
    fcur->setfilter("");
  }
  else
    fcur->setfilter("(TIPODIST==\"\")&&(NDIST==\"\")");
  const TRecnotype n = fcur->items();
  fcur->freeze();

  _base_page_no = 0;
  _formdse->find_field('F',last_page,2).set(""); // Azzera nr documenti
  _formdse->find_field('F',last_page,3).set(""); // Azzera tot documenti
  _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
}

void TEmissione::enable_dettaglio(TForm& form) const
{
  TForm_subsection* fss = form.exist_field('B', odd_page, "RIGHE_EFFETTO");
  const bool dett = _msk->get_bool(F_DETTAGLIO);
  if (fss)
    fss->show(dett);
  else
  {
    if (dett)
    {
      warning_box(FR("Il modulo %s non prevede la stampa dei dettagli:\n"
                  "E' necessario aggiungere la sezione RIGHE_EFFETTO"),
                  (const char*)form.name());
    }
  }
}

// gestione emissione  effetti/distinte su moduli cartacei
void TEmissione::print()
{
  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->curr().put(EFF_TIPODIST,tipodist);
  _rel->curr().put(EFF_NDIST,ndist);
  _rel->curr().put(EFF_NRIGADIST,1);
  _rel->lfile().setkey(4);
  _rel->read();
  long codabi = _rel->curr().get_long(EFF_CODABIP);
  const char tipocf = _rel->curr().get_char(EFF_TIPOCF);
  const char tipopag = _rel->curr().get_char(EFF_TIPOPAG);
  
  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
  TFilename nomeform; // compongo il nome del form
  if (emis == 1)
  {
    nomeform.format("r%c%c%05ld.frm",tipocf, tipopag, codabi);
    if (!nomeform.exist())                // se non esiste
      nomeform.overwrite("00000", 3);     // elimino codice banca
    if (!nomeform.exist())                // se non esiste
      nomeform.overwrite("0", 2);         // elimino tipo pagamento
    if (!nomeform.exist())                // se non esiste 
       nomeform = "rb.frm";               // utilizzo quello generico
    _formrb = new TRiba_form(nomeform);
    enable_dettaglio(*_formrb);
    print_rb(tipost,ndist,tipodist,is_vis);
  }
  else
  {
    nomeform.format("d%c%c%05ld.frm",tipocf, tipopag, codabi);// compongo il nome del form
    if (!nomeform.exist())                // se non esiste
      nomeform.overwrite("00000", 3);     // elimino codice banca
    if (!nomeform.exist())                // se non esiste
      nomeform.overwrite("0", 2);         // elimino tipo pagamento
    if (!nomeform.exist())                // se non esiste
       nomeform = "dse.frm";              // utilizzo quello generico
    _formdse = new TDistinta_form(nomeform, _firmrel);
    enable_dettaglio(*_formdse);
    _formdse->set_order(tipord);
    print_dse(tipost,ndist,tipodist,is_vis);
  }
  printer().close();
}

// 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 TString16 code(s.get(0));
  TString valore;  // Attenzione pu� essere molto lunga (descrizione di 5 righe)

  if (code == "_IMPORTO")
  {
  // gestione dei campi relativi all'importo dell'effetto. Setta il valore da
  // solo se e' in valuta (cambia anche la picture)
  // sintassi: _IMPORTO
    const TEffetto effetto(cursor()->file().curr());
    const bool in_valuta = effetto.in_valuta();
    real importo = effetto.importo(in_valuta);
    cf.set(importo.string());
  } 
  else if (code == "_BANCAP")
  {
  // gestione dei campi relativi alla banca di presentazione dell'effetto
  // sintassi: _BANCAP
    TCursor* cur = cursor();
    if (cur->curr().get_int(EFF_NDIST) > 0)
    {
      valore = cur->curr(-204).get("S0");
      valore << ' ' << cur->curr(-202).get("S0");
      valore.trim();
      cf.set(valore);
      cf.put_paragraph(valore);
    }
  }
  else 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
    TEffetto effetto(cursor()->file().curr());// = eff.curr();
    long num = effetto.numero();
    const bool in_valuta = effetto.in_valuta();
    bool condition = (effetto.fatt(num));//TRUE se effetto non raggruppato
    TToken_string dati; effetto.dati_fatt(num, in_valuta, dati);
    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 << '\n';
        }
        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);
    return (TRUE);
  }
  else
  if (code == "_CLI")
  {
  // gestione dei campi relativi al cliente  a cui si riferisce un effetto
  // sintassi: _CLI,<macro>
  // dove: <macro> � uno delle macro seguenti:
  //       "!IND"         INDIRIZZO + NR. CIVICO
  //       "!LOCALITA"    LOCALITA
  //       "!PIAZZA"      COMUNE + PROVINCIA
  //       "!CAP"         CAP
  //       "!RAGSOC"      Ragione sociale
  // Queste macro sono state implementate per permettere di utilizzare
  // L'indirizzo di spedizione effetti memorizzato in LF_CFVEN->CODINDEFF
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      TRelation* rel = relation();

      const bool pick_normal = rel->curr(LF_CFVEN).get_int(CFV_CODINDEFF) == 0;
      
      if (in=="IND")
      {
        const TRectype& cli = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP);
        valore = cli.get(pick_normal ? CLI_INDCF : IND_INDIR);
        const TString& civ = cli.get(pick_normal ? CLI_CIVCF : IND_CIV);
        if (civ.not_empty())
          valore << ", " << civ;
      } else
      if (in=="PIAZZA" || in=="COMUNE")
      {
          const TRectype& com = rel->curr(pick_normal ? LF_COMUNI : -213);
          valore = com.get(COM_DENCOM);
          const TString& prov = com.get(COM_PROVCOM);
          if (prov.not_empty())
            valore << " (" << prov << ")";
      } else
      if (in=="LOCALITA")
      {
        const TRectype& cli = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP);
        valore = cli.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
      } else
      if (in=="RAGSOC")
        valore = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_RAGSOC : IND_RAGSOC); else  
      if (in=="CAPCF")
        valore = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_CAPCF : IND_CAP);
    }
    cf.put_paragraph(valore);
    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)
{
  const char* 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";
  
  if (_cursor) delete _cursor; // Added by Guy
  _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 == "_IMPORTO")
  {
  // gestione dei campi relativi all'importo dell'effetto. Setta il valore da
  // solo se e' in valuta (cambia anche la picture)
  // sintassi: _IMPORTO
    TEffetto effetto(cursor()->file().curr());
    const bool in_valuta = effetto.in_valuta();
    real importo = effetto.importo(in_valuta);
    cf.set(importo.string());
    return (TRUE);
  }
  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);
    return (TRUE);
  }
  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")
      {
        valore = _firmrel->curr().get("RAGSOC");
        valore.strip_double_spaces();
        cf.set(valore);
      } else
      if (in == "CFPI")
      {
        valore = _firmrel->curr(LF_ANAG).get("PAIV");
        valore.trim();
        if (valore.empty())
        {
          valore = _firmrel->curr(LF_ANAG).get("COFI");
          valore.trim();
        }
        cf.set(valore);
      } else
      if (in == "CFPI")
      {
        valore = _firmrel->curr(LF_ANAG).get("PAIV");
        valore.trim();
        if (valore.empty())
        {
          valore = _firmrel->curr(LF_ANAG).get("COFI");
          valore.trim();
        }
        cf.set(valore);
      }
    }
    valore = cf.get();
    cf.put_paragraph(valore);
    cf.set("");
    return (TRUE);
  }
  if (code == "_CLI")
  {
  // gestione dei campi relativi al cliente  a cui si riferisce un effetto
  // sintassi: _CLI,<macro>
  // dove: <macro> � uno delle macro seguenti:
  //       "!IND"         INDIRIZZO + NR. CIVICO
  //       "!PIAZZA"      COMUNE + PROVINCIA
  //       "!CAP"         CAP
  //       "!RAGSOC"      Ragione sociale
  // Queste macro sono state implementate per permettere di utilizzare
  // L'indirizzo di spedizione effetti memorizzato in LF_CFVEN->CODINDEFF
    TString in(s.get());
    if (in[0]=='!')
    {
      in.ltrim(1);
      TRelation* rel = relation();

      const bool pick_normal = rel->lfile(LF_CFVEN).get_int(CFV_CODINDEFF) == 0;

      if (in=="IND")
      {
        valore = rel->lfile(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_INDCF : IND_INDIR);
        in = rel->lfile(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_CIVCF : IND_CIV);
        if (in.not_empty())
          valore << ", " << in;
      }
      else
        if (in=="PIAZZA" || in=="COMUNE")
        {
          valore = rel->curr(pick_normal ? LF_COMUNI : -213).get(COM_DENCOM);
          in = rel->curr(pick_normal ? LF_COMUNI : -213).get(COM_PROVCOM);
          if (in.not_empty())
            valore << " (" << in << ")";
        } else
        if (in=="LOCALITA")
        {
          const TRectype& cli = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP);
          valore = cli.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
        } else
        if (in=="RAGSOC")
          valore = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_RAGSOC : IND_RAGSOC);
        else  
          if (in=="CAPCF")
            valore = rel->curr(pick_normal ? LF_CLIFO : LF_INDSP).get(pick_normal ? CLI_CAPCF : IND_CAP);
    }
    cf.set(valore);
    cf.put_paragraph(valore);
    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
    TEffetto effetto(cursor()->file().curr()); //= eff.curr();
    long num = effetto.numero();
    TToken_string dati; effetto.dati_fatt(num, FALSE, dati);
    const int elem = dati.items();
    TString80 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")
      {
        TString descfatt;
        for (int i = 0; i < elem; i+=3)
        {
          descfatt << dati.get(i);
          descfatt << ' ';
          descfatt << dati.get(i+1);
          descfatt << '\n';
        }
        cf.set(descfatt);
      }
    }
    valore = cf.get();
    cf.put_paragraph(valore);
    return (TRUE);
  }
  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();
    cf.set(valore);
    cf.put_paragraph(valore);
    cf.set("");
    return TRUE;
  }
  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());
    CHECK(in[0]=='!',"Macro _FISSO senza carattere '!'");
    in.ltrim(1);
    in.trim();
    valore = in;
  }
  else 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();
  }
  else 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());
    CHECK(in[0]=='!',"Macro _NRIBA senza carattere '!'");
    in.ltrim(1);
    if (in=="NUM")
    {
      valore.cut(0);
      valore << cur.pos() + 1;
    }
    else if (in=="TOT")
    {
      valore.cut(0);
      valore << items;
    }
    else if (in=="NREC")
    {
      valore.cut(0);
      int rec = items * 7 + 2;
      valore << rec;
    }
    else 
      CHECKS (TRUE,"Sotto-Macro _NRIBA non definita",(const char *)in); 
  }
  else 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

    TString in(s.get());
    CHECK(in[0]=='!',"Macro _DITTA senza carattere '!'");
    in.ltrim(1);
    if (in=="RAGSOC")
    {
      const TRectype& ditte = app().firm_rel().curr();
      const TString& ragsoc = ditte.get("RAGSOC");
      in = s.get();
      if (in == "0")
      {
        valore.cut(0);
        valore = ragsoc.left(30);
        valore.trim();
        valore << ' ' << ragsoc.mid(30);
        valore.trim();
      }
      else
      {
        TParagraph_string string(ragsoc,24);
        const int indice = atoi(in);
        valore = string.get(indice-1);
      }
    } else 
    if (in == "CFPI")
    {
      const TRectype& curr = app().firm_rel().curr(LF_ANAG);
      valore = curr.get("PAIV");
      valore.trim();
      if (valore.empty())
      {
        valore = curr.get("COFI");
        valore.trim();
      }
    }
    else
      CHECKS(FALSE, "Sotto-Macro _DITTA non definita: ",(const char *)in); 
  }
  else if (code == "_DEBITORE")
  {
    // gestione di campi della ditta corrente
    // sintassi: _DEBITORE,<macro>,<opzione>
    // dove: <macro> � uno delle macro seguenti:
    //       "!RAGSOC"     ragione sociale
    //       "!CFPI"       Partita IVA o Codice fiscale 
    //       "!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
    const bool pick_normal = cur.curr(LF_CFVEN).get_int(CFV_CODINDEFF) == 0;
    
    TRectype& clifo_1 = cur.curr(LF_CLIFO);
    TRectype& clifo_2 = cur.curr(pick_normal ? LF_CLIFO : LF_INDSP);
    TRectype& comuni  = cur.curr(pick_normal ? LF_COMUNI: -213);
    
    TString in(s.get());
    CHECK(in[0]=='!',"Macro _DEBITORE senza carattere '!'");
    in.ltrim(1);
    if (in=="RAGSOC")
    {
      TString ragsoc = clifo_2.get(pick_normal ? CLI_RAGSOC : IND_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);
    }
    else if (in=="IND")
    {
      valore = clifo_2.get(pick_normal ? CLI_INDCF : IND_INDIR);
      valore.trim();
      valore << ' ' << clifo_2.get_int(pick_normal ? CLI_CIVCF : IND_CIV);
      valore.trim();
    }
    else if (in=="INDIRIZZO")
    {
      valore = clifo_2.get(pick_normal ? CLI_INDCF : IND_INDIR);
      valore.trim();
      valore << ' ' << clifo_2.get_int(pick_normal ? CLI_CIVCF : IND_CIV);
      valore.trim();
      valore << ' ' << clifo_2.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
      valore.trim();
    }
    else if (in=="COMUNE")
    {
      valore = comuni.get("DENCOM");
      if (valore.blank())
        valore = clifo_2.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
      valore.trim();
    }
    else if (in=="PROV")
    {
      valore = comuni.get("PROVCOM");
      valore.trim();
    }
    else if (in=="LOCALITA")
    {
      valore = clifo_2.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
      valore.trim();
    }
    else if (in=="LOCALITA+COMUNE")
    {
      valore = clifo_2.get(pick_normal ? CLI_LOCCF : IND_LOCALITA);
      valore.trim();   
      if (valore.not_empty())
        valore << " (" << comuni.get("DENCOM") << ')';
      else
        valore = comuni.get("DENCOM");
      valore.trim();
    }
    else if (in=="CFPI")
    {
      valore = clifo_1.get("PAIV");
      valore.trim();
      if (valore.empty())
      {
        valore = clifo_1.get("COFI");
        valore.trim();
      }
    }
    else    
      CHECKS (TRUE,"Sotto-Macro _DEBITORE non definita",(const char *)in); 
  }
  else if (code == "_BANCA")
  {
  // gestione dei campi relativi alla banca d'appoggio dell'effetto
  // sintassi: _BANCA
    valore = cur.curr(-401).get("S0");
    valore << ' ' << cur.curr(-402).get("S0");
  }
  else 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 = cur.curr();
    long num = effetto.numero();
    TString descfatt;
    if (tracciato_setif())
    {
      TToken_string dati; effetto.dati_fatt(num, FALSE, dati);
      int elem = dati.items();
      for (int i = 0; i < elem; i+=3)
      {
        descfatt << dati.get(i);
        descfatt << " ";
        descfatt << dati.get(i+1);
        descfatt << " ";
      }
    }
    else
    {
      TToken_string dati; effetto.altridati_fatt(num, dati);
      int elem = dati.items();
      TString16 str;
      for (int i = 0; i < elem; i+=3)
      {
        if (i!=0)
          descfatt << "/";
        str = dati.get(i); str.trim(); // codnum
        if (str.not_empty()) descfatt << str << ' ';
        
        str = dati.get(); str.trim(); // numdoc
        if (str.not_empty()) descfatt << str;

        str = dati.get(i); // anno (2 cifre)
        str.trim();
        if (str.len() >= 2)
          descfatt << ' ' << str.right(2);
      }
    }  
    const 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);
        valore.trim();
      }
    }
  }
  else 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
    const TString in(s.get());
    CHECK(in[0]=='!',"Macro _IMPORTO senza carattere '!'");
    if (in=="!ADD")
    {

      real importo = cur.curr(LF_EFFETTI).get(EFF_IMPORTO);
      if (_codice_moneta == 'E')
        importo *= CENTO;         
      importo.round(0);  
      add_tot_importi(importo);
      valore = importo.string(13,0);
    }
    else if (in=="!TOT")
    {
      const real& importo = tot_importi();
      valore = importo.string("##############@");
      set_tot_importi(ZERO);
    }
    else
      CHECKS (TRUE,"Sotto-Macro _IMPORTO non definita",(const char *)in);
  } 
  else if (code == "_CODSIA")
  {
    TConfig cnf(CONFIG_DITTA, "ef");
    valore = cnf.get("CODSIA");
  }
  else if (code == "_CODMON")
  {
    valore.format("%c", _codice_moneta);
  }
  else NFCHECK("Macro non definita: %s", (const char *)code);
  
  str = valore;
}

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