// cg3400 - Stampa libro giornale

#include <isam.h>
#include <mask.h>
#include <utility.h>
#include <tabutil.h>
#include <urldefid.h>
#include <printapp.h>
#include <config.h>
#include <progind.h>

#include <mov.h>
#include <rmov.h>
#include <rmoviva.h>
#include <nditte.h>
#include <anagr.h>
#include <anafis.h>
#include <anagiu.h>
#include <causali.h>
#include <comuni.h>
#include <pconti.h>
#include <clifo.h>
#include <occas.h>

#include "conto.h"
#include "cglib03.h"
#include "cg2103.h"
#include "cg3400a.h"
#include "cg3400b.h"

HIDDEN const char*  REAL_PICTURE = "###.###.###.###";
HIDDEN const char*  REAL_TOT_PIC = "#.###.###.###.###";
HIDDEN const char*  RIP_TOT_PIC  = "###.###.###.###";
HIDDEN const int    RIGHE_MODULO = 66;
HIDDEN const int    RIGHE_FOOTER = 10;

HIDDEN TString256 tmp;

HIDDEN int date2esc(const TDate& d, int* prevesc = NULL);

HIDDEN enum descr { causale, conto, operazione };

class CG3400_application : public TPrintapp
{
  static bool mask_a_cod_reg   (TMask_field& f, KEY k);
  static bool data_a_hndl      (TMask_field& f, KEY k);
  static bool data_da_hndl     (TMask_field& f, KEY k);
  static bool mask_b_ripristina(TMask_field& f, KEY k);

public:
  TRigaiva_array  _iva_array;
  TRelation  * _rel;
  TCursor    * _cur;
  TRectype   * _RecPartoDa, *_RecArrivoA;

  TString16    _reg_cod;
  TString80    _reg_descr;
  TDate        _data_da, _data_a, _last_data;
  real         _tot_dare, _tot_avere;              // valori di partenza
  real         _tot_dare_progr, _tot_avere_progr;  // progressivi anno in corso
  real         _tot_dare_progr_ap, _tot_avere_progr_ap;  // progr. anno prec.
  real         _tot_dare_gg , _tot_avere_gg ;      // giornalieri
  real         _tot_dare_ap , _tot_avere_ap ;      // giornalieri anno precedente
  real         _tot_dare_generale, _tot_avere_generale; // tot. generali
  long         _nprog_da, _nprog_mov;
  int          _num_rig, _stampa_width, _stampa_len;

  TParagraph_string*      _descr_conto;  
  TParagraph_string*      _descr_causale;  
  TParagraph_string*      _descr_operazione;  

  int          _pagine_stampate, _pagine_numerate, _stampa_ok, _pagina_da;
  TDate        _data_corr, _data_succ;
  int          _mese_corr, _mese_succ;
  int          _last_header;    // prima riga di intestazione "libera"

  bool         _libro_giornale_iva_unico, _libro_cronologico, _stampa_intesta;
  bool         _gia_settata_riga_mov;   // per la stampa no iva

  TString80    _ragsoc, _paiva, _comunefis, _viafis;
  TString16    _provfis, _cap, _occfpi;
  TString80    _cofi;
  TString16    _caus;

  TLocalisamfile * _com, *_clifo,*_pconti,*_nditte,*_anag, *_causali;
  TTable         *_tabreg, *_tabval, *_tabes; 

public:
  int          _ae;         // anno esercizio di ALLA_DATA
  int          _tipo;       // tipo del registro
  int          _annoEsMov;  // anno esercizio letto da mov
  bool         _stampa_definitiva;
  TDate         _inizioEs, _fineEs;    // date inizio e fine esercizio
  TString256    _riporto;               // riga di stampa per i riporti
  TString256    _intes;         // riga di stampa per intestazione
  virtual void preprocess_header();
  virtual void preprocess_footer();
  virtual bool preprocess_page(int, int);
  virtual print_action postprocess_page(int, int);
  virtual bool preprocess_print(int, int);
  virtual print_action postprocess_print(int, int);
  virtual void postclose_print();
  virtual bool user_create();
  virtual bool user_destroy();
  virtual void set_page    (int, int);
  void         set_rows (int, int);
  void         set_page_132(int, int);
  void         set_page_198(int, int);
  void         setta_righe_indirizzo(char tipocf, long codcf);
  int          setta_righe_iva();
  void         setta_righe_valuta();
  void         setta_righe_descr(TParagraph_string*, enum descr);
  void         calcola_iva();
  void         init_print();
  virtual bool cancel_hook();
  virtual bool set_print(int);

  void         init_totals();
  int          stampa_intestazione_ditta();
  int          set_header_132();
  int          set_header_198();

  bool leggi_tabreg(const char * codreg, int annoes);
  int  ultimo_esercizio();        // ritorna l'ultimo anno esercizio
  void aggiorna_tabreg(int, int);
  void aggiorna_mov();
  void scrivi_numgio(long);
  void set_totali_giorno(const TDate& giorno, const int righeivasettate);
  void get_dati_ditta ();
  const char*   SimboloValuta (const char * cod);
  const char*   get_descr_caus (const char * codcaus);    
  TRectype&     look_com (const char * cod);

  CG3400_application() {};
  virtual ~CG3400_application() {};
};

HIDDEN CG3400_application& app() { return (CG3400_application&) main_app(); }

//////////////////////////////////////////////////////////////////////////
// Funzioni legate ai parametri ditta
//////////////////////////////////////////////////////////////////////////
HIDDEN bool libro_giornale_iva_unico()
{
  TConfig conf(CONFIG_DITTA);
  return conf.get_bool("StLgiU");
}

HIDDEN bool libro_cronologico()
{
  TConfig conf(CONFIG_DITTA);
  return conf.get_bool("GsLbCn");
}

TRectype& CG3400_application::look_com (const char * cod)
{
  _com->zero();
  _com->put(COM_COM, cod);
  if (_com->read() == NOERR)
    _com->zero();

  return _com->curr();
}

const char * CG3400_application::SimboloValuta (const char * cod)
{
  TTable& tab_val = *_tabval;
  TString16 codtab; 

  codtab.format ("%-3s", cod); 

  tab_val.zero();
  tab_val.put("CODTAB", codtab);
  tab_val.read();

  if (tab_val.good())
    tmp = tab_val.get("S7");
  else 
    tmp = "";

  return tmp;
}

const char * CG3400_application::get_descr_caus (const char * codcaus)
{
  TLocalisamfile& caus = *_causali;
  
  caus.zero();
  caus.put (CAU_CODCAUS, codcaus);
  if (caus.read() != NOERR) caus.zero();

  tmp = caus.get(CAU_DESCR);
  return tmp;
} 

void CG3400_application::get_dati_ditta ()
{
  TString16          codanagr;
  char               tipoa;

  _nditte->zero();
  _nditte->put(NDT_CODDITTA, get_firm());   
  _nditte->read();

  if (_nditte->bad()) _nditte->zero();

  _ragsoc  = _nditte->get(NDT_RAGSOC);
  codanagr = _nditte->curr().get(NDT_CODANAGR);
  tipoa    = _nditte->curr().get_char(NDT_TIPOA);

  if (tipoa == 'F')
  {           
    /*
       TString80 cognome(_ragsoc.cut(1,30));
       TString80 nome(_ragsoc.cut(30,50));
       _ragsoc = cognome; _ragsoc << " " << nome;
       */    
  }

  _anag->setkey(1);
  _anag->zero();
  _anag->put (ANA_TIPOA, tipoa);
  _anag->put (ANA_CODANAGR, codanagr);
  _anag->read();
  if (_anag->bad()) _anag->zero();
  
  _cofi      = _anag->get(ANA_COFI);
  _paiva     = _anag->get(ANA_PAIV);
  //  _ragsoc    = _anag->get(ANA_RAGSOC);
  _comunefis = _anag->get(ANA_COMRF);

  if (_comunefis.empty()) 
    _comunefis   = _anag->get(ANF_COMRES);

  TRectype dep = look_com (_comunefis);

  _comunefis   = dep.get(COM_DENCOM);
  _provfis     = dep.get(COM_PROVCOM);
  _cap         = dep.get(COM_CAPCOM);
  
  if (_comunefis.empty()) 
  {
    _viafis      = _anag->get(ANA_INDRF);
    _viafis.rtrim();
    _viafis << " " << _anag->curr().get (ANA_CIVRF); 
  }
  else
  {
    _viafis      = _anag->get(ANA_INDRES);
    _viafis.rtrim();
    _viafis << " " << _anag->get (ANA_CIVRES); 
  }
}

bool CG3400_application::user_create()
{
  _ae = 0;
  _tabreg = new TTable ("REG");
  _tabval = new TTable ("%VAL");
  _tabes  = new TTable ("ESC");

  _nditte  = new TLocalisamfile(LF_NDITTE); 
  _anag    = new TLocalisamfile (LF_ANAG); 
  _com     = new TLocalisamfile(LF_COMUNI);
  _clifo   = new TLocalisamfile(LF_CLIFO);
  _pconti  = new TLocalisamfile(LF_PCON);
  _causali = new TLocalisamfile(LF_CAUSALI);

  _descr_conto      = new TParagraph_string ("",21);
  _descr_operazione = new TParagraph_string ("",28);
  _descr_causale    = new TParagraph_string ("",20);

  //  disable_print_menu();

  _rel = new TRelation (LF_MOV);
  _rel->add (LF_RMOV,    "NUMREG=NUMREG");
  _rel->add (LF_RMOVIVA, "NUMREG=NUMREG");

  _cur = new TCursor (_rel, "", 2);   // usa la chiave 2 su MOV

  _RecPartoDa = new TRectype(_cur->file(LF_MOV).curr());
  _RecArrivoA = new TRectype(_cur->file(LF_MOV).curr());

  add_cursor (_cur);

  add_file (LF_MOV);
  add_file (LF_RMOV);
  add_file (LF_RMOVIVA);
  return TRUE;
}

bool CG3400_application::user_destroy()
{
  delete _rel;
  delete _cur;
  delete _RecPartoDa;
  delete _RecArrivoA;

  delete _com; delete _clifo; delete _causali; delete _pconti;
  delete _nditte; delete _anag; 
  delete _tabreg; delete _tabes; delete _tabval;

  delete _descr_conto;
  delete _descr_operazione;
  delete _descr_causale;
  delete _nditte;
  delete _anag;
  return TRUE;
}

void CG3400_application::aggiorna_mov()
{
  TLocalisamfile mov(LF_MOV);
  TProgind prnd (mov.items(), "Aggiornamento movimenti ...", FALSE, TRUE);

  long nprog = _nprog_da;

  mov.curr() = *_RecPartoDa;

  for (mov.read(_isgteq, _lock); mov.curr() < *_RecArrivoA && !mov.eof(); mov.next(_lock))
  {
    const bool gia_stampato = mov.get_bool(MOV_STAMPATO);
    if (!gia_stampato)
    {
      mov.put (MOV_STAMPATO, TRUE);
      mov.put (MOV_NUMGIO, nprog);
      mov.rewrite();
      nprog++;
    }
    else
      mov.reread(_unlock);

    prnd.addstatus(1);
  }
  mov.reread(_unlock);
}

void CG3400_application::scrivi_numgio(long nprog)
{
  TLocalisamfile &mov = current_cursor()->file(LF_MOV);

  mov.reread(_lock);
  mov.put (MOV_NUMGIO, nprog);
  mov.rewrite();
}

// NB
// Se si usa un codice @g dopo un
// @b (bold) il primo pezzo perde qualche carattere in visualizzazione
// (in stampa su carta non ho provato)
//
void CG3400_application::set_totali_giorno(const TDate& data, const int righeiva)
{
  int       r = 1 + righeiva;
  TString   dep(_stampa_width);
  TString16 frm;  

  if (_stampa_width == 132)
    frm = "@b@10g";
  
  if (_tot_avere_gg != ZERO || _tot_dare_gg != ZERO)
  {
    dep = frm;
    dep << "Operazioni del "; dep << data.string();

    //    set_row (r++, "%s                 Dare: %r Avere: %r", (const char *)dep,&_tot_dare_gg, &_tot_avere_gg );
    set_row (r++, "@52g%s @95g%r @112g%r", (const char *)dep, &_tot_dare_gg, &_tot_avere_gg );
    _tot_dare_gg  = _tot_avere_gg = ZERO;
  }

  if ( _tot_avere_ap != ZERO || _tot_dare_ap != ZERO )
  {                
    dep = frm;
    dep << "Operazioni del "; dep << data.string() << " " << "Anno precedente";

    //    set_row (r++, "%s Dare: %r Avere: %r", (const char *)dep, &_tot_dare_ap,&_tot_avere_ap );
    set_row (r++, "@52g%s @95g%r @112g%r", (const char *)dep, &_tot_dare_ap,&_tot_avere_ap );
    _tot_avere_ap = _tot_dare_ap = ZERO;
  } 

  set_row (r, "");      // Lascio una riga vuota dopo il totale
}

// --------------------------------------------------------------------------
//
// STAMPA A 132
//
// --------------------------------------------------------------------------
void CG3400_application::set_page_132 (int file, int counter)
{
  int r = 1;
  switch (file)  
  {
  case LF_MOV:
    if (_libro_giornale_iva_unico)
    {
      if (_stampa_definitiva)                     
      {
        set_row(r,"Operazione n. #-3ld", &_nprog_mov);
        set_row(r," del @d",             FLD(LF_MOV, MOV_DATAREG) );
        set_row(r," documento n. @3pn",  FLD(LF_MOV, MOV_NUMDOC, "###") );
        set_row(r," del @d @s",          FLD(LF_MOV, MOV_DATADOC), 
                FLD(LF_MOV, MOV_DESCR));
        set_row(r," Anno di competenza @4pn", FLD(LF_MOV, MOV_ANNOES, "@@@@") );
      }
      else
      { 
        set_row(r,"Operazione n. @3,lpn", FLD(LF_MOV, MOV_NUMREG, "###"));
        set_row(r," del @d",              FLD(LF_MOV, MOV_DATAREG) );
        set_row(r," documento n. @3pn",   FLD(LF_MOV, MOV_NUMDOC, "###") );
        set_row(r," del @d @s",           FLD(LF_MOV, MOV_DATADOC), 
                FLD(LF_MOV, MOV_DESCR));
        set_row(r," Anno di competenza @4pn", FLD(LF_MOV, MOV_ANNOES, "@@@@") );            
      }
    }
    else
      if (!_gia_settata_riga_mov)
      {
        set_row (r, "Operazioni del @d", FLD(LF_MOV,MOV_DATAREG));
        _gia_settata_riga_mov = TRUE;
      }
    
    break;
    
  case LF_RMOV:
    if (_libro_giornale_iva_unico)
    {
      if (!_stampa_definitiva) 
        set_row (r, "%3d", _num_rig);

      //      set_row (r, "@5g@3s",  FLD(LF_MOV, MOV_CODCAUS));
      set_row (r, "@56g@pn", FLD(LF_RMOV, RMV_GRUPPO, "@@."));
      set_row (r, "@pn",     FLD(LF_RMOV, RMV_CONTO , "@@."));
      set_row (r, "@pn",     FLD(LF_RMOV, RMV_SOTTOCONTO, "@@@@@@"));
    }
    else   // no libro_giornale_iva_unico
    {
      if (_stampa_definitiva) 
        set_row (r, "#-3ld", &_nprog_mov);
      else
        set_row (r, "@3,rn", FLD(LF_RMOV, RMV_NUMREG));
      set_row (r, "@4g@d",   FLD(LF_RMOV, RMV_DATAREG));
      set_row (r, "@13g@pn", FLD(LF_RMOV, RMV_GRUPPO, "@@."));
      set_row (r, "@pn",     FLD(LF_RMOV, RMV_CONTO , "@@."));
      set_row (r, "@pn",     FLD(LF_RMOV, RMV_SOTTOCONTO, "@@@@@@"));
    }
    break;

  default:
    break;
  }
}

// --------------------------------------------------------------------------
//
// STAMPA A 198
//
// --------------------------------------------------------------------------
void CG3400_application::set_page_198 (int file, int counter)
{
  int r = 1;
  switch (file)
  {
  case LF_MOV:
    break;
  case LF_RMOV:
    set_row (r, "@d", FLD(LF_RMOV,RMV_DATAREG));
    set_row (r, "@10g@pn/@pn", FLD(LF_RMOV,RMV_NUMREG,"####"),
             FLD(LF_RMOV,RMV_NUMRIG,"##"));
    set_row (r, " @d", FLD(LF_RMOV,MOV_DATADOC));
    set_row (r, " @pn",FLD(LF_RMOV,MOV_NUMDOC));

    set_row (r, "@38g@pn",FLD(LF_RMOV, RMV_GRUPPO, "@@."));
    set_row (r, "@pn",FLD(LF_RMOV, RMV_CONTO , "@@."));
    set_row (r, "@pn",FLD(LF_RMOV, RMV_SOTTOCONTO, "@@@@@@"));

    set_row (r, "#50t", &_descr_conto);
    set_row (r, "@80g@3s", FLD(LF_MOV, MOV_CODCAUS));
    set_row (r, "#50t", &_descr_causale);

    //      set_row (r, "@50s", FLD(LF_RMOV, RMV_DESCR));
    set_row (r, "#50t", &_descr_operazione);

    // Dare e avere sono settati nella preprocess_page
    // Cosi' pure l'indirizzo nel caso di gestione libro cronologico
    // _descr contiene la descrizione conto o la ragione sociale
    // v. preprocess_page
    break;
  case LF_RMOVIVA:
    break;
  default:
    break;
  }
}


void CG3400_application::set_page (int file, int counter)
{
  if (_libro_giornale_iva_unico)
    set_page_132(file, counter);
  else
    if (_stampa_width == 132)
      set_page_132(file, counter);
    else
      set_page_198(file, counter);
}

print_action CG3400_application::postprocess_print(int file, int counter)
{
  switch (file)  {
  case LF_MOV:
    *_RecArrivoA = _cur->file(LF_MOV).curr();
    break;
  default:
    break;
  }
  return NEXT_PAGE;
}

void CG3400_application::postclose_print()
{
  if (_stampa_definitiva)
  {
    const int ultima_fatta = printer().getcurrentpage();
    const int stampate = ultima_fatta - _pagina_da + 1;  
    
    if (yesno_box("La stampa e' corretta ? "))
    {
      _pagina_da = -1;
      aggiorna_mov ();
      aggiorna_tabreg (_pagina_da, stampate);
    }
  }
}

void CG3400_application::preprocess_footer()
{
  TString           progr_dare_ap(22), progr_avere_ap(22);
  TString256        riga, frm;
  bool              ap = FALSE;
  int               r=2;

  if (_tot_avere_progr_ap != ZERO || _tot_dare_progr_ap != ZERO)
  {
    progr_dare_ap  = _tot_dare_progr_ap.string(REAL_TOT_PIC);
    progr_avere_ap = _tot_avere_progr_ap.string(REAL_TOT_PIC);
    ap = TRUE;
  }
  
  if (_stampa_width == 132)
    frm = "@b@59g"; 
  else
    frm = "@b@100g"; 
  
  if (_cur->pos() >= _cur->items()-1)    // se sono sull'ultimo
  {
    const TFixed_string progr_dare  ( _tot_dare_progr.string(REAL_TOT_PIC));
    const TFixed_string progr_avere ( _tot_avere_progr.string(REAL_TOT_PIC));  
    
    riga = frm;
    riga << format("Totale progressivi                 @95g%s @112g%s", 
                   (const char *) progr_dare, (const char *) progr_avere);    
    
    set_footer (r++, (const char*) riga);    
    
    if (ap)
    {
      riga.format("%sTotale progressivi anno precedente @95g%s @112g%s", 
                  (const char*)  frm,
                  (const char *) progr_dare_ap,  (const char *) progr_avere_ap);
      set_footer (r++, (const char*) riga);
    }
    
    _tot_dare_generale  = _tot_dare_progr  + _tot_dare_progr_ap;
    _tot_avere_generale = _tot_avere_progr + _tot_avere_progr_ap;
    const TFixed_string dts(_tot_dare_generale.string(REAL_TOT_PIC));
    const TFixed_string ats(_tot_avere_generale.string(REAL_TOT_PIC));
    
    riga = frm;
    riga << format ("Totale progressivi generali @95g%s @112g%s", (const char *) dts, (const char *) ats);                     
    set_footer (r++, (const char*) riga);          
  }
else      // Non ancora totale generale
{
  real dt = _tot_dare_progr  + _tot_dare_progr_ap;
  real at = _tot_avere_progr + _tot_avere_progr_ap;
  const TFixed_string dts(dt.string(REAL_TOT_PIC));
  const TFixed_string ats(at.string(REAL_TOT_PIC));

  riga = frm;
  riga << format ("A riportare @95g%s @112g%s@r", (const char *) dts,
                  (const char *) ats);
  set_footer (r++, (const char*) riga);          
}
}

int CG3400_application::stampa_intestazione_ditta()
{
  int r=1;
#if XVT_OS == XVT_OS_SCOUNIX                     
  TString riga(_stampa_width);
#endif

  get_dati_ditta();

#if XVT_OS == XVT_OS_SCOUNIX                     
  riga.fill('-'); 
  set_header(r, riga);
#endif

  set_header (++r, "Ditta: %s %s %s %s %s", (const char *)_ragsoc, 
              (const char *)_viafis, (const char *)_cap, 
              (const char *)_comunefis, (const char *)_provfis); 
  
  _intes = format ("Partita iva %s @24gCodice fiscale %s %s @117gData @>", 
                   (const char*)_paiva, (const char*)_cofi, 
                   _stampa_definitiva ? "" : "STAMPA DI PROVA");
  
  set_header (++r, "%s", (const char*) _intes);
  
  r += 2;

  return r;
}

////////////////////////////////////////////////////////////////////
// HEADER 198
////////////////////////////////////////////////////////////////////
int CG3400_application::set_header_198()
{
  int r=1;
  TString riga(_stampa_width);
  TString16 data_da = _data_da.string();
  TString16 data_a  = _data_a.string();

  if (_stampa_intesta || !_stampa_definitiva) 
    r = stampa_intestazione_ditta();

  //  set_header(r, "@bCodice libro:@r %s %s @bdalla data:@r %s @balla data:@r %s @bEsercizio:@r %04d",
  set_header(r, "Codice libro: %s %s dalla data: %s alla data: %s Esercizio: %04d",
             (const char *) _reg_cod, (const char *) _reg_descr,
             (const char *) data_da,  (const char *) data_a, _ae);
  r++;

  riga.fill('-'); 
  set_header(r, riga);
  r++;

  set_header(r, " Data    Numero       Documento"); 

  riga = "Anno S";
  riga.right_just(_stampa_width);
  if (_libro_cronologico)
    riga.overwrite("    Codice conto Descrizione conto"); 
  else
    riga.overwrite("      Codice"); 

  set_header(r, "%s", (const char*) riga); 
  r++;

  riga = "Comp B";
  riga.right_just(_stampa_width);
  if (_libro_cronologico)
    riga.overwrite("Registr. Registraz. data e numero             Generalita' cliente/fornitore@82gCod.Causale@102gDescrizionee operazione@142gDARE@164gAVERE");
  else
    riga.overwrite("Registr. Registraz. data e numero    Conto     Descrizione conto@82gCod.Causale@102gDescrizionee operazione@142gDARE@164gAVERE");

  set_header(r, "%s", (const char*) riga); 
  r++;

  riga.fill('-'); 
  set_header(r, riga);
  r++;

  return r;
}

////////////////////////////////////////////////////////////////////
// HEADER 132
////////////////////////////////////////////////////////////////////
int CG3400_application::set_header_132()
{
  int r=1;
  TString riga(_stampa_width);
  TString16 data_da = _data_da.string();
  TString16 data_a  = _data_a.string();

  if (_stampa_intesta || !_stampa_definitiva) 
    r = stampa_intestazione_ditta();

#if XVT_OS != XVT_OS_SCOUNIX                     
  if (_stampa_intesta || !_stampa_definitiva)
    set_background("W4l{1 1 133 1}W4l{1 4 133 4}W1l{1 8 133 8}");  
  else
  {
    set_background("W4l{1 1 133 1}W1l{1 5 133 5}");
    r++;
  }
#else
  riga.fill('-'); 
  set_header(r, riga);
#endif

  //  set_header(r++, "@bCodice libro:@r %s %s @bdalla data:@r %s @balla data:@r %s @bEsercizio:@r %04d",
  set_header(r++, "Codice libro: %s %s @69gdalla data: %s alla data: %s @117gEsercizio: %04d",
             (const char *) _reg_cod, (const char *) _reg_descr,
             (const char *) data_da,  (const char *) data_a, _ae);

  ////////////////////////////////////////////////////////////////////
  // LIBRO GIORNALE IVA UNICO
  ////////////////////////////////////////////////////////////////////
  if (_libro_giornale_iva_unico)
  {
    set_header(r, "Ri"); 
    if (_libro_cronologico)
      set_header(r, "@60gCodice        Conto"); 

    set_header(r, "@113gImporti@131gS");
    r++;

    set_header(r, "ga@6gCod.Causale@34gDescrizione operazione");
    if (_libro_cronologico)
      set_header(r, "@60gGeneralita' cliente/fornitore"); 
    
    set_header(r, "@106gDARE@122gAVERE@131gB");
    r++;
  }
  else
    ////////////////////////////////////////////////////////////////////
    // NO LIBRO GIORNALE IVA UNICO
    ////////////////////////////////////////////////////////////////////
  {
    set_header(r, "Numero@12gDocumento@28gCodice@115gImporti@127g  A S"); 
    r++;
    if (_stampa_definitiva)
      set_header(r, "Riga"); 
    else
      set_header(r, "Regist."); 

    set_header(r, "@10gData e numero@28gConto@41gDescrizione conto@68gDescrizione operazione@106gDare@122gAvere@127g  C B");
    r++;
  }

#if XVT_OS == XVT_OS_SCOUNIX                     
  riga.fill('-'); 
  set_header(r, riga);
#endif
  
  return r;
}

void CG3400_application::preprocess_header()
{
  int r      = _last_header + 1;
  int pag    = printer().getcurrentpage();
  TString16    frm;
  real         riporto_dare, riporto_avere;
  
  if (pag > 0)   // Stampa riporti
  {
    riporto_dare  = _tot_dare_progr  + _tot_dare_progr_ap;
    riporto_avere = _tot_avere_progr + _tot_avere_progr_ap;

    TString dare (riporto_dare.string(RIP_TOT_PIC));
    TString avere(riporto_avere.string(RIP_TOT_PIC));
    // RIP_TOT_PIC adesso e' lunga 15

    if (_stampa_width == 132)
      frm = "@b@84g";
    else
      frm = "@b@100g";

    _riporto = frm;
    
    _riporto << format ("Riporto: @95g%15s @112g%15s", (const char *) dare,
                        (const char *) avere );

    set_header (r++, "%s", (const char *) _riporto);

    set_header (r, "");
  }
}

//
// PREPROCESS_PRINT
//
// Se non ci sono items nel cursore (= se non ci sono movimenti) 
// la stampa e' abortita.
//
// stampa_ok = -1  ->  la stampa precedente era OK
// stampa_ok = x   ->  la stampa precedente non e' andata a buon fine
//                     ed era partita dalla pagina x.
//
// Se la stampa precedente e' andata male, setto la pagina corrente a
// quella salvata in stampa_ok, e la pagina da cui parte la stampa vera e 
// propria a quella che mi dice l'utente:
//
//           set_page_number (stampa_ok)
//           setfrompage     (pagina_da)
//
bool CG3400_application::preprocess_print(int file, int counter)
{
  int i;
  switch (file)
  {
  case LF_MOV:
    
    _gia_settata_riga_mov = FALSE;  // Stampa o no la riga di mov (solo se 
    // NO stampa giornale_iva_unico                                        
    _num_rig            = 1;
    _iva_array.destroy();
    
    if (_cur->items() == 0)
      return warning_box ("Non ci sono movimenti.\nLa stampa e' annullata");

    _nprog_mov   = _nprog_da;

    *_RecPartoDa = _cur->file(LF_MOV).curr();

    for (i=1; i<RIGHE_FOOTER; i++)
      set_footer(i, "%s", " ");

    break;
  default:
    break;
  }
  return TRUE;
}

bool CG3400_application::cancel_hook()
{
  int ultima_fatta = printer().getcurrentpage();
  int stampate = ultima_fatta - _pagina_da + 1;

  if (yesno_box ("Interrompo la stampa ?"))
  {
    if (_stampa_definitiva)
      aggiorna_tabreg (_pagina_da, stampate);
    return TRUE;
  }
  else
    return FALSE;
}

print_action CG3400_application::postprocess_page(int file, int counter)
{
  int righe_iva_settate=0;
  static bool nuovo_mese = FALSE;
  
  if (counter) 
  {
    if (nuovo_mese) {
      printer().formfeed();
      nuovo_mese = FALSE;
    }
    return NEXT_PAGE;
  }

  switch (file)
  {
  case LF_MOV:

    reset_print();

    if (_libro_giornale_iva_unico)
      righe_iva_settate = setta_righe_iva();

    _cur->save_status();
    ++(*_cur);
    _data_succ = _cur->file(LF_MOV).get_date(MOV_DATAREG);
    _mese_succ = _data_succ.month();
    --(*_cur);
    _cur->restore_status();

    //    if (_data_corr != _data_succ || _cur->lastrec()) 
    if (_data_corr != _data_succ || _cur->pos() == _cur->items())
    {
      nuovo_mese = (_mese_succ != _mese_corr);
      set_totali_giorno(_data_corr, righe_iva_settate);
      _gia_settata_riga_mov = FALSE;
      return REPEAT_PAGE;
    }
    else
      _gia_settata_riga_mov = TRUE;

    if (righe_iva_settate > 0)
      return REPEAT_PAGE;
    
    break;

  case LF_RMOVIVA:
  default:
    break;
  }
  return NEXT_PAGE;
}

//
// PREPROCESS_PAGE
//
// Non stampo niente se:
//
// 1. STAMPATO = TRUE     
//       OPPURE
// 2. non ci sono righe di RMOV
//
bool CG3400_application::preprocess_page(int file, int counter)
{
  static char   cf;
  int           g, c;
  long          s;
  bool          gia_stampato=FALSE;
  static bool   settata_causale=FALSE;
  TString80     rmv_descr;
  char          sezione;
  real          importo;
  TString16     frm;
  TConto        tc;
  
  if (counter) return TRUE;

  switch (file)  {
    
  case LF_MOV:

    _num_rig=1;
    settata_causale = FALSE;
    
    _iva_array.destroy();

    if (!_cur->is_first_match(LF_RMOV)) return FALSE;

    gia_stampato = _cur->file(LF_MOV).get_bool(MOV_STAMPATO);

    if (gia_stampato)
      if (_stampa_definitiva)
        return FALSE;
      else {
        if (_stampa_width == 132)
          set_row (1, "@131g*");  // stampo un * se mov. gia stampato
        else
          set_row (1, "@197g*");
      }

    if (_libro_giornale_iva_unico) _nprog_mov++; 

    _data_corr   = _cur->file(LF_MOV).get_date(MOV_DATAREG);
    _mese_corr   = _data_corr.month();
    _annoEsMov   = _cur->file(LF_MOV).get_int(MOV_ANNOES);
    _caus        = _cur->file(LF_MOV).get(MOV_CODCAUS);  
    _occfpi      = _cur->file(LF_MOV).get(MOV_OCFPI);  
    
    break;

  case LF_RMOV: 

    _num_rig++; 
    
    if (!_libro_giornale_iva_unico) _nprog_mov++;     

    if (cf > ' ') {  // Per pulire le righe di indirizzo eventualmente settate prima.
      reset_row(2); reset_row(3);
    }       
    
    g         = _cur->file(LF_RMOV).get_int(RMV_GRUPPO);
    c         = _cur->file(LF_RMOV).get_int(RMV_CONTO);
    s         = _cur->file(LF_RMOV).get_long(RMV_SOTTOCONTO);
    cf        = _cur->file(LF_RMOV).get_char(RMV_TIPOC);
    sezione   = _cur->file(LF_RMOV).get_char (RMV_SEZIONE);
    importo   = _cur->file(LF_RMOV).get_real (RMV_IMPORTO);    
    rmv_descr = _cur->file(LF_RMOV).get(RMV_DESCR);

    tc.set(g,c,s,cf);

    if (_stampa_width == 132) 
    {
      _descr_causale->set_width(20);
      _descr_operazione->set_width(28);
      _descr_conto->set_width(21);      
    }
    else                          // se a 198 non spezzo le descrizioni
    {
      _descr_causale->set_width(198);
      _descr_operazione->set_width(198);
      _descr_conto->set_width(198);
    }

    *_descr_operazione  = (const char *)rmv_descr;
    *_descr_conto       = tc.descrizione();
    
    // Il codice e descrizione della causale vanno solo sulla prima riga
    if (!settata_causale)
    {
      set_row (1, "@5g%3s", (const char*) _caus );
      *_descr_causale     = get_descr_caus(_caus);    
      setta_righe_descr (_descr_causale, causale);
      settata_causale = TRUE;
    }
    
    setta_righe_descr (_descr_operazione, operazione);
    setta_righe_descr (_descr_conto, conto);        
    
    if (cf > ' ')
      if (_libro_cronologico)
        setta_righe_indirizzo(cf, s);    
    
    if (sezione == 'D')
    {
      if (_annoEsMov != _ae)
      {
        _tot_dare_ap        += importo;    // prog. anno precedente
        _tot_dare_progr_ap  += importo;   
      }
      else
      {
        _tot_dare_gg    += importo;    // prog. giornalieri
        _tot_dare_progr += importo;      // prog. generali
      }
      
      if (_stampa_width == 132)
        frm = "@95g%r";
      else
        frm = "@142g%r";      
    }
    else
    {                                   
      if (_annoEsMov != _ae)
      {
        _tot_avere_ap       += importo;
        _tot_avere_progr_ap += importo;
      }        
      else
      {
        _tot_avere_gg    += importo;
        _tot_avere_progr += importo;
      }

      if (_stampa_width == 132)
        frm = "@112g%r";
      else
        frm = "@164g%r";            
    }
    
    set_row (1, (const char *)frm, &importo);
    
    break;

  case LF_RMOVIVA: 

    if (_libro_giornale_iva_unico)
    {
      calcola_iva ();
      setta_righe_valuta();
    }
    break;

  default: 
    break;
  }
  return TRUE;
}

void CG3400_application::calcola_iva()
{
  TString  codiva;
  int      tipocr, tipodet;
  real     impo, impos;
  TRectype iva (_cur->file(LF_RMOVIVA).curr());

  if (!iva.empty())
  {
    impo    = iva.get_real (RMI_IMPONIBILE);
    impos   = iva.get_real (RMI_IMPOSTA);
    tipocr  = iva.get_int (RMI_TIPOCR);
    tipodet = iva.get_int (RMI_TIPODET);
    codiva  = iva.get (RMI_CODIVA);
    _iva_array.add_riga(impo,impos,codiva,tipodet,0,ZERO,ZERO);
  }
}

void CG3400_application::setta_righe_descr(TParagraph_string* str, enum descr des)
{
  int   i = 1;
  TString16 frm;
  const char * r;
  
  switch (des)
  {
  case causale:    // lunga 20
    if (_libro_giornale_iva_unico)
      frm = "@10g%.20s";
    else
      frm = "@48g%.20s";
    break;
  case conto:     // lunga 21
    if (_libro_giornale_iva_unico)
      frm = "@69g%s";
    else
      frm = "@26g%s";
    break;
  case operazione:  // lunga 28
    if (_libro_giornale_iva_unico)
      frm = "@31g%s";
    else
      frm = "@69g%s";
    break;
  default:
    break;
  }
  while ((r = str->get()) != NULL)
    set_row (i++, (const char*)frm, r);
}

// NB
// Questa funzione ritorna il numero di righe che ha settato.
// Se questo e' diverso da 0 viene fatta una REPEAT_PAGE
// Attenzione quindi se si modifica la variabile r
int CG3400_application::setta_righe_iva()
{
  int r=0, j;

  for (j = 0; j < _iva_array.items(); j++)
  {
    TRigaiva& riga = (TRigaiva&)_iva_array[j];
    r = j+1;
    set_row(r, "Imponibile@12g%r",    &riga._imponibile);
    set_row(r, "@31gImposta@39g%r",   &riga._imposta);
    set_row(r, "@58gCodice Iva@68g%3s", (const char*)riga._codiva);
    switch (riga._tipodet)
    {
    case 0 : set_row(r, "@73gDetraibile");
             break;
           case 1 : set_row(r, "@73gIndetraibile su op.es.");
             break;
           case 3 : set_row(r, "@73gPassaggi interni");
             break;
           case 9 : set_row(r, "@73gIndetraibile art.19");
             break;
           default: break;   
           } 
  } 
  _iva_array.destroy();
  set_row (j+1, "");  // lascio una riga vuota dopo tutto cio'
  return r; 
}

void CG3400_application::setta_righe_valuta()
{      
  TString16 simbolo, codval;
  bool     intracom;

  codval    = current_cursor()->file(LF_MOV).get(MOV_CODVAL);
  intracom  = current_cursor()->curr(LF_RMOVIVA).get_bool(RMI_INTRA); 
  simbolo   = SimboloValuta(codval);

  if ((codval != "LIT") && intracom)
  {
    reset_row(1);
    set_row(1,"Corr.in lire@14g@pN",
            FLD(LF_RMOVIVA,RMI_CORRLIRE,"###.###.###.###.###"));
    set_row(1,"@34gCorr.in valuta@49g@pN",
            FLD(LF_RMOVIVA,RMI_CORRVALUTA,"###.###.###.###.###"));
    if (simbolo.not_empty())
      set_row(1,"@53g%.5s", (const char *)simbolo);
    else
      set_row(1,"@53g%.3s", (const char *)codval);
  }
}

// Cerca l'indirizzo del C/F.
// Legge CLIFO o OCCAS a seconda di _occas      
// Setta le righe 2 e 3 che vengono poi resettate al record successivo
void CG3400_application::setta_righe_indirizzo(char tipocf, long codcf)
{
  TString16 comune, prov, comcf, capcf, civcf, statocf;
  TString80 viacf;

  if (_occfpi.not_empty())   // => e' un occasionale...
  {
    TLocalisamfile& occ = _cur->file(LF_OCCAS);

    viacf = occ.get (OCC_INDIR);
    civcf = occ.get (OCC_CIV);
    capcf = occ.get (OCC_CAP);
    comcf = occ.get (OCC_COM);
  } 
else 
{
  _clifo->zero();
  _clifo->put(CLI_CODCF, codcf);
  _clifo->put(CLI_TIPOCF, tipocf);

  if (_clifo->read() == NOERR)
  {
    viacf   = _clifo->get(CLI_INDCF);
    civcf   = _clifo->get(CLI_CIVCF);
    comcf   = _clifo->get(CLI_COMCF);
    capcf   = _clifo->get(CLI_CAPCF);
    statocf = _clifo->get(CLI_STATOCF);
  }
}

TRectype dep = look_com (comcf);
comune       = dep.get(COM_DENCOM);
prov         = dep.get(COM_PROVCOM);

if (_libro_giornale_iva_unico)
{
  set_row (2, "@69g%s %s",    (const char *)viacf, (const char *)civcf);
  set_row (3, "@69g%s %s %s", (const char *)capcf, (const char *)comune,
           (const char *)prov);
}
else  // no libro iva unico. Cambia la colonna di inizio
{
  set_row (2, "@26g%s %s",    (const char *)viacf, (const char *)civcf);
  set_row (3, "@26g%s %s %s", (const char *)capcf, (const char *)comune,
           (const char *)prov);
}
}

//
// Lettura/aggiornamento tabella registri
//
void CG3400_application::aggiorna_tabreg(int partito_da, int stampate)
{
  TString16 codtab;

  codtab.format ("%04d%-3s", _ae, (const char*) _reg_cod);

  _tabreg->zero();
  _tabreg->put("CODTAB", codtab);
  _tabreg->read();

  if (_tabreg->good())
  {
    _tabreg->put ("I1", _pagine_stampate + stampate);
    _tabreg->put ("I7", partito_da);   // partito_da = -1 se stampa OK
    _tabreg->put ("I6", _nprog_mov);
    _tabreg->put ("R1", _tot_dare_generale);
    _tabreg->put ("R2", _tot_avere_generale);
    _tabreg->put ("D3", _data_a);
    _tabreg->rewrite();
  }
}

int CG3400_application::ultimo_esercizio()
{
  TString16 sanno;
  TTable ese("ESC");

  ese.zero();         
  //  ese.last();   // Sembra che non vadi ?!? 
  ese.first();
  sanno = ese.get("CODTAB"); sanno.cut(4);

  const int anno = atoi(sanno);

  return anno;
}

bool CG3400_application::leggi_tabreg(const char * reg_cod, 
                                      int reg_anno)
{
  TString16 codtab;

  if (reg_anno == 0)
    reg_anno = ultimo_esercizio();

  _ae = reg_anno;

  codtab.format ("%04d%-3s", reg_anno, reg_cod);

  _tabreg->zero();
  _tabreg->put("CODTAB", codtab);
  const bool ok = (_tabreg->read() == NOERR);
  
  if (!ok) _tabreg->zero();
  
  _pagine_stampate = _tabreg->get_int("I1");
  _pagine_numerate = _tabreg->get_int("I2");
  _stampa_ok       = _tabreg->get_int("I7");
  _nprog_da        = _tabreg->get_long ("I6");
  _tot_dare        = _tabreg->get_real ("R1");
  _tot_avere       = _tabreg->get_real ("R2");
  _last_data       = _tabreg->get_date ("D3");
  _stampa_intesta  = _tabreg->get_bool ("B9");
  _reg_descr       = _tabreg->get ("S0");
  _tipo            = _tabreg->get_int("I0");
  
  return ok;
}

// Calcola l'anno di esercizio di una data                                
// Certified 99%
HIDDEN int date2esc(const TDate& d, int* prevesc)
{                   
  if (prevesc) *prevesc = 0;
  TTable esc("ESC");
  for (int err = esc.first(); err == NOERR; err = esc.next())
  {
    const TDate ia(esc.get("D0"));   // Data inizio esercizio
    const TDate fa(esc.get("D1"));   // Data fine esercizio
    app()._inizioEs = ia;
    app()._fineEs   = fa;
    const anno = esc.get_int("CODTAB");  
    if (d >= ia && d <= fa)
      return anno;
    if (prevesc) *prevesc = anno; 
  } 
  return 0;
}

//-----------------------------------------------------------------------
//
// MASCHERE
//
//-----------------------------------------------------------------------

bool CG3400_application::data_a_hndl (TMask_field& f, KEY k)
{
  TMask&          m = f.mask();          

  if (f.to_check(k))
  {
    const TDate     data_a(f.get());                  
    const int       ae = date2esc(data_a); // Anno esercizio
    TString16       dep(data_a.string());
    
    if (dep.empty()) return TRUE;                   
    
    app()._ae = ae;
    
    if (ae == 0) 
      return f.error_box("La data specificata non appartiene a nessun esercizio");
  }
  
  if (k == K_ENTER)
  {
    const bool      definitiva = m.get_bool(STAMPA_DEF);
    const TDate     data_da(m.get(DATA_DA));    
    const TDate     data_a(f.get());                  
    TString16       dtda(data_da.string());   
    const int       ae = app()._ae; 
    const TMask_field& fld_dtda = m.field(DATA_DA);

    // Controlli sulle date    

    if (definitiva)  
    {     
      if (dtda.not_empty())  // senno' ci metto inizioEs
      {
        if (data_da < app()._inizioEs || data_a > app()._fineEs);
        return f.warning_box("Le date specificate non appartengono allo stesso esercizio");
        if (data_da > data_a)
          return f.warning_box("La data di partenza non puo' essere maggiore della data finale");
      }
    }

    /*********************
      // Controllo il registro
      const TString16 codreg(m.get(CODREG));
      const TMask_field& fld_reg = m.field(CODREG);
      TRegistro reg(codreg, ae);
      
      if (!reg.ok()) 
      return fld_reg.warning_box("Non trovo il libro giornale %s per l'esercizio %d", 
      (const char *) codreg, ae);
      
      if (reg.tipo() != 5)
      return fld_reg.warning_box("Il registro %s per l'anno %d non e' di tipo libro giornale",
      (const char *) codreg, ae);
      **************/
  }  // if K_ENTER

  return TRUE;
}

bool CG3400_application::data_da_hndl(TMask_field& f, KEY k)
{
  TMask&              m = f.mask();          
  if (f.to_check(k))
  {
    const TDate         data_da (f.get());
    const TString16     data_a(m.get(DATA_A));    
    const int           ae_data_da = date2esc(data_da);
    const TString16     dep(data_da.string());
    
    if (dep.empty() || data_a.empty())
      return TRUE;
    
    if (app()._ae != 0)
      if (app()._ae != ae_data_da)
        return f.error_box("Le due date non appartengono allo stesso esercizio");
  }

  if (k == K_ENTER)
  {
    const bool      definitiva = m.get_bool(STAMPA_DEF);
    const TDate     data_a(m.get(DATA_A));                      
    const TDate     data_da(f.get());                  
    TString16       dtda(data_da.string());   

    // Controlli sulle date    

    // se la stampa e' di prova DALLA_DATA e' obbligatoria
    if (!definitiva)  
      if (dtda.empty()) 
        return f.warning_box("Manca la data di partenza");
    
    if (dtda.not_empty())
      if (data_da > data_a)
        return f.warning_box("La data di partenza non puo' essere maggiore della data finale");
  }
  return TRUE;
}

//
// MASK_A_COD_REG
// 
// Aggiorna il campo PAGINA_DA della maschera
//
// Legge la tabella dei registri e controlla se la stampa precedente
// era andata a buon fine.  
// Se no, riempie il campo PAGINA_DA con il valore precedente.
// Se si', mette semplicemente l'ultimo numero di pagina precedente + 1
//
bool CG3400_application::mask_a_cod_reg (TMask_field& f, KEY k)
{
  if (k == K_TAB)
  {
    TMask&    m = f.mask();
    CG3400_application& a = (CG3400_application&) main_app();    
    const bool definitiva = m.get_bool(STAMPA_DEF);
    const int  ae = app()._ae;

    const TString16 reg_cod(f.get()); 

    if (reg_cod.empty()) return TRUE;

    bool reg_ok = a.leggi_tabreg(reg_cod, a._ae);

    // Output da qui della descrizione del registro e dell'anno
    m.set(REG_DESC,  a._reg_descr);
    m.set(ANNO_ESER, a._ae);

    // CHECKTYPE NORMAL abolito! (nella maschera non ho l'anno...
    if (!reg_ok) 
      return f.warning_box("Registro inesistente");
    
    if (app()._tipo != 5)
      return f.warning_box("Il registro %s per l'anno %d non e' di tipo libro giornale",
                           (const char *) reg_cod, ae);

    if (definitiva)
    {
      if (a._stampa_ok == -1)     // stampa precedente andata bene
        m.set(PAGINA_DA, a._pagine_stampate+1);
      else
        m.set(PAGINA_DA, a._stampa_ok);
    }
  }
  return TRUE;
}

//
// mask_b_ripristina
//
// Se premo il bottone <Ripristina> rimetto i valori precedenti
// dentro ai campi (per ripetere la stampa)
//
bool CG3400_application::mask_b_ripristina (TMask_field& f, KEY k)
{
  if (k == K_TAB) 
  {
    CG3400_application& a = (CG3400_application&)main_app();    
    f.mask().set(PROGR_DARE, a._tot_dare.string());
    f.mask().set(ULTIMA_DATA, a._last_data.string());
    f.mask().set(N_RIGA_STAMPATO, a._nprog_da);
  }
  return TRUE; 
}

void CG3400_application::init_print()
{
  if (_stampa_len != 0) 
    printer().formlen(_stampa_len);
  else
    printer().formlen(RIGHE_MODULO); 

  printer().footerlen(RIGHE_FOOTER);
  
  reset_print();
  reset_header();
  reset_footer();
  set_background();

  set_real_picture (REAL_PICTURE);
  set_print_zero(TRUE);

  if (_stampa_width == 1) 
    _stampa_width = 132;
  else 
    _stampa_width = 198;

  force_setpage(TRUE);      
  
  printer().set_from_page (_pagina_da);
  
  if (_stampa_ok != -1)       // la stampa precedente era andata male
    set_page_number (_stampa_ok); 
  
  if (_stampa_width == 132)
    _last_header = set_header_132();
  else
    _last_header = set_header_198();

}

void CG3400_application::init_totals()
{
  _tot_dare_ap        = ZERO;
  _tot_avere_ap       = ZERO;
  _tot_dare_progr_ap  = ZERO;
  _tot_avere_progr_ap = ZERO;
  _tot_dare_gg        = ZERO;
  _tot_avere_gg       = ZERO;
  _tot_dare_generale  = ZERO;
  _tot_avere_generale = ZERO;
  _tot_dare_progr     = _tot_dare;
  _tot_avere_progr    = _tot_avere;
}

bool CG3400_application::set_print(int)
{
  TMask ma ("cg3400a");
  KEY   tasto;

  ma.set_handler (CODREG, mask_a_cod_reg);
  ma.set_handler (DATA_A,  data_a_hndl);
  ma.set_handler (DATA_DA,  data_da_hndl);

  tasto = ma.run();

  if (tasto == K_ENTER)
  {
    _libro_giornale_iva_unico = libro_giornale_iva_unico();
    _libro_cronologico        = libro_cronologico();

    _reg_cod           = ma.get(CODREG);
    _stampa_definitiva = ma.get_bool(STAMPA_DEF);
    _data_da           = ma.get(DATA_DA);
    _data_a            = ma.get(DATA_A);
    _pagina_da         = ma.get_int(PAGINA_DA);
    _stampa_width      = ma.get_int(STAMPA_WIDTH);
    _stampa_len        = ma.get_int(STAMPA_LEN);

    // Se stampa definita DALLA_DATA e' l'ultima data di stampa del
    // registro, se indicata, oppure la data di inizio esercizio
    if (_stampa_definitiva)
      if (_last_data.ok()) 
        _data_da = _last_data;
      else
        _data_da = _inizioEs;

    leggi_tabreg(_reg_cod, _ae);
    
    init_print();
    init_totals();
    
    TRectype da (_cur->file(LF_MOV).curr());
    TRectype a  (_cur->file(LF_MOV).curr());

    da.zero(); a.zero();
    da.put(MOV_DATAREG, _data_da);
    a.put (MOV_DATAREG, _data_a);

    _cur->setregion(da, a);

    if (_stampa_definitiva)
    {
      TMask mb("cg3400b");
      mb.set_handler (DLG_RIPRISTINA, mask_b_ripristina);
      mb.set (PROGR_DARE,      _tot_dare.string());
      mb.set (N_RIGA_STAMPATO, _nprog_da);
      mb.set (ULTIMA_DATA,     _last_data.string());
      tasto = mb.run();
    }
    return TRUE;
  }
  return (tasto == K_ENTER);
}

int  cg3400  (int argc, char * argv[])
{
  CG3400_application app;
  app.run(argc, argv, "Stampa libro giornale");
  return TRUE;
}

