// cg3400 - Stampa libro giornale

#include <config.h>
#include <mask.h>
#include <tabutil.h>
#include <printapp.h>
#include <progind.h>
#include <utility.h>
#include <urldefid.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*  TOT_PICTURE  = "#.###.###.###.###";
HIDDEN const char*  REAL_PICTURE = "###.###.###.###";

HIDDEN const int    RIGHE_FOOTER = 3;

HIDDEN const int    WCAUS132    = 20;
HIDDEN const int    WOPER132    = 28;
HIDDEN const int    WCONTO132   = 35;
HIDDEN const int    POSCONTO    = 74;

HIDDEN const int    DARE132     = 95;
HIDDEN const int    AVERE132    = 112;
HIDDEN const int    DARE198     = 150;
HIDDEN const int    AVERE198    = 174;

  const int SCRITTA = 26;  // prima era 29               
  const int TOTDARE132 = 88; // prima era 92
  const int SEZA132 = 108;  // prima era 111
  const int TOTAVERE132 = 110; // prima era 112

HIDDEN TString256 tmp;

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

HIDDEN enum descr { causale, conto, operazione };

class TContoOccas : public TBill
{
  long      _s;
  char      _t;
  TString16 _occfpi;
  TString80 _descrizione;
  
public:
  const TContoOccas& set(int g = 0, int c = 0, long s = 0L, char t = ' ', 
                         const char* d = NULL, int r = -1, const char* occfpi = NULL);
  
  const TString& descrizione();
  
  TContoOccas() : _occfpi(NULL) {};
  virtual ~TContoOccas() {};
};

const TContoOccas& TContoOccas::set(int g, int c, long s, char t,const char* d, int r, const char* occfpi)
{
  _s = s; _t = t;
  TBill::set(g,c,s,t,d,r); 
  _occfpi = occfpi;   
  return *this;
}

const TString& TContoOccas::descrizione()
{
  bool      really_occas = FALSE;
  
  if (_occfpi.not_empty())
  {
    TLocalisamfile clifo(LF_CLIFO);
    clifo.zero();
    clifo.put(CLI_CODCF,  (long)_s);
    clifo.put(CLI_TIPOCF, _t);
    const bool clifo_ok = (clifo.read() == NOERR);
    if (clifo_ok) really_occas = clifo.get_bool(CLI_OCCAS);
  }

  if (_occfpi.empty() || !really_occas)
    _descrizione = TBill::descrizione();
  else
  {
    TLocalisamfile occ(LF_OCCAS);
    occ.zero();
    occ.put(OCC_CFPI, _occfpi);
    if (occ.read() != NOERR) occ.zero();
    _descrizione = occ.get("RAGSOC");
  } 
  return _descrizione;
}

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);
  static bool mask_b_warning   (TMask_field& f, KEY k);

  static bool filter_func(const TRelation * r);  
  static bool filtra_reg (const TRelation * r);  

private:
  TRelation*    _rel;
  TCursor*      _cur;
  TRectype*     _RecPartoDa, *_RecArrivoA;    
  int           _ae;         // anno esercizio di ALLA_DATA
  int           _tipo;       // tipo del registro
  int           _annoEsMov;  // anno esercizio letto da mov
  TString16     _reg;
  int           _anno_iva;
  bool          _stampa_definitiva;
  bool          _MovGiaStampato;
  bool          _gia_settato_ariportare;
  bool          _forza_ariportare;
  bool          _nuovo_mese;    // Finito il mese ?
  long          _num_rig;
  real          _importo;
  char          _sezione;
  //    TParagraph_string*      _descr_conto;                
  
public:
  TDate         _inizioEs, _fineEs;    // date inizio e fine esercizio
  TRigaiva_array  _iva_array;

  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_gg_ap , _tot_avere_gg_ap ;      // giornalieri anno precedente
  real         _tot_dare_generale, _tot_avere_generale; // tot. generali
  long         _nprog_da, _nprog_mov;
  int          _stampa_width, _stampa_len;

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

  bool         _stampa_stesso_registro;
  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;
  
  TLocalisamfile*   _attiv;  // da togliere in futuro (?)
  
  TTable         *_tabreg, *_tabval, *_tabes, *_tabiva; 

public:

  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 void postclose_print();
  //  virtual bool cancel_hook();
  virtual bool set_print(int);
  
  virtual bool user_create();
  virtual bool user_destroy();
  
  void set_rows (int file, int counter);
  int  setta_righe_indirizzo(char tipocf, long codcf, int rdesc);
  int  setta_righe_iva();
  int  setta_righe_valuta(int start_riga);
  int  setta_righe_descr(TParagraph_string&, enum descr);
  
  void fill_page(int start_riga, int righe_iva);  
  void calcola_iva();
  void init_print();
  bool init_cursor();

  void init_totals();
  int  stampa_intestazione_ditta();
  int  set_headers();

  bool leggi_tabreg(const char * codreg, int annoes);
  bool controlla_mov_aep();

  bool competenza_ep() const { return _ae != _annoEsMov; }
  bool competenza_ec() const { return !competenza_ep(); } // tertium non datur ?

  void aggiorna_tabreg(int, int);
  void aggiorna_mov();
  int  set_totali_giorno(const TDate& giorno, const int righeivasettate);
  int  set_totali_pagina(int r);
  void get_dati_ditta ();

  const char* get_descr_caus (const char * codcaus);    
  TRectype&   look_com (const char * cod);
  const char* get_codiva_des(const char* codiva);
  void        get_date_aep(int aep, TDate* in, TDate* fin);
  void        update_totals (char sezione, real& importo);
  void        set_reg_filter(TMask& m);
  
  CG3400_application() {};
  virtual ~CG3400_application() {};
};

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

bool CG3400_application::filtra_reg(const TRelation * r)
{           
  const TRectype& rec = r->lfile().curr();
  const int anno = atoi(rec.get("CODTAB").left(4));

  if (app()._ae)  
  {
    if (anno == app()._ae)
      return TRUE;
    else
      return FALSE;
  }
  return TRUE;
}

bool CG3400_application::filter_func(const TRelation * r)
{           
  const TRectype& recmov = r->lfile().curr();
  TRectype& recrmov      = r->lfile(LF_RMOV).curr();
  const long numreg      = recmov.get_long("NUMREG");

  // Scarto SEMPRE i provvisori
  TString16 provvis = recmov.get(MOV_PROVVIS);
  if (provvis.trim().not_empty())
    return FALSE;
  
  // In caso di NO libro con iva scarta quelli che non hanno righe contabili
  if (!app()._libro_giornale_iva_unico)
  {
    recrmov.zero();
    recrmov.put("NUMREG", (long)numreg);  
    //    TRectype cfr(r->lfile(LF_RMOV).curr());
    if (r->lfile(LF_RMOV).read())          
    {
      const long numreg2 = recrmov.get_long("NUMREG");
      if (numreg2 != numreg)
        return FALSE;
      else
        return TRUE;
    }  
  }
  return TRUE;
}


//////////////////////////////////////////////////////////////////////////
// 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::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);

  _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);
  _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");
  _tabiva = new TTable ("%IVA");
  
  _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);
  _attiv   = new TLocalisamfile(LF_ATTIV);  // da togliere 
  
  _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: DATAREG+NUMREG

  _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 _tabiva;

  delete _attiv; // da togliere in futuro
  
  delete _nditte;
  delete _anag;
  return TRUE;
}

void CG3400_application::aggiorna_mov()
{
  TLocalisamfile& mov = _cur->file(LF_MOV);
  long nprog = _nprog_da + 1;
  
  const TRectype da(*_RecPartoDa);  
  const TRectype  a(*_RecArrivoA);
  _cur->setregion(da, a);
  (*_cur) = 0L;
  
#ifndef DBG
  TProgind prnd (_cur->items(), "Aggiornamento movimenti ...", FALSE, TRUE);  
#endif
  //  for (mov.read(_isgteq, _lock); mov.curr() < *_RecArrivoA && !mov.eof(); mov.next(_lock))

  for (  ; _cur->pos() < _cur->items(); ++(*_cur))
  {
#ifdef DBG
    long numreg = _cur->file(LF_MOV).get_long("NUMREG");
    TString datareg(_cur->file(LF_MOV).get("DATAREG"));
    //    message_box("Numreg: %ld Datareg: %s", numreg, (const char*)datareg);
#endif        
    const bool gia_stampato = _cur->file(LF_MOV).get_bool(MOV_STAMPATO);
    if (!gia_stampato)
    {
      _cur->file(LF_MOV).put (MOV_STAMPATO, TRUE);
      _cur->file(LF_MOV).put (MOV_NUMGIO, nprog);
      mov.rewrite();
      nprog++;
    }
    //    else mov.reread(_unlock);
#ifndef DBG
    prnd.addstatus(1);
#endif    
  }
  //  mov.reread(_unlock);
}

int CG3400_application::set_totali_giorno(const TDate& data, const int righeiva)
{
  int       r;
  char      dep[200];
  const int SHIFT = 15;
  const int STACC = 51 + SHIFT;

  r = righeiva == 0 ? 1 : righeiva + 1;

// Se e' l'unico totale lo stampo anche se e' zero
  if (competenza_ec() || (_tot_avere_gg != ZERO || _tot_dare_gg != ZERO))
  {
    TString td(_tot_dare_gg.string (TOT_PICTURE));
    TString ta(_tot_avere_gg.string(TOT_PICTURE));

    sprintf(dep, "@b@%dgTotale operazioni del %s @%dg%c %s @%dg%c @%dg%s", 
            _stampa_width == 132 ? SCRITTA : DARE198-STACC,
            data.string(),
            _stampa_width == 132 ? TOTDARE132 : DARE198-2,
            'D',            
            (const char*)td, 
            _stampa_width == 132 ? SEZA132 : DARE198+20,
            'A',                        
            _stampa_width == 132 ? TOTAVERE132 : AVERE198,                
            (const char*)ta
            );
    
    set_row (r++, "%s", dep);
    _tot_dare_gg  = _tot_avere_gg = ZERO;
  }
  
  if (competenza_ep() || (_tot_avere_gg_ap != ZERO || _tot_dare_gg_ap != ZERO))
  {                
    TString tdp(_tot_dare_gg_ap.string(TOT_PICTURE));
    TString tap(_tot_avere_gg_ap.string(TOT_PICTURE));

    sprintf (dep, "@b@%dgTotale operazioni del %s Anno precedente @%dg%c %s @%dg%c @%dg%s", 
             _stampa_width == 132 ? SCRITTA : DARE198-STACC,
             data.string(),
             _stampa_width == 132 ? TOTDARE132 : DARE198-2,
             'D',            
             (const char*)tdp,                             
             _stampa_width == 132 ? SEZA132 : DARE198+20,             
             'A',            
             _stampa_width == 132 ? TOTAVERE132 : AVERE198,                
             (const char*)tap
             );

    set_row (r++, "%s", dep);

    _tot_avere_gg_ap = _tot_dare_gg_ap = ZERO;
  } 
  return r;  
}


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


void CG3400_application::preprocess_footer()
{
  TString           progr_dare_ap(22), progr_avere_ap(22);
  TString           progr_dare(25), progr_avere(25), dts(25), ats(25);
  TString256        riga;
  bool              ap = FALSE;
  int               r=2;
  const int STUMB  = 42;
  real              dt, at;
  
  reset_footer();
  
  if (_tot_avere_progr_ap != ZERO || _tot_dare_progr_ap != ZERO)
  {
    progr_dare_ap  = _tot_dare_progr_ap.string(TOT_PICTURE);
    progr_avere_ap = _tot_avere_progr_ap.string(TOT_PICTURE);
    ap = TRUE;
  }
  
  //
  // Non stampo "A riportare" 
  // SE :
  // 1. E' gia' stato stampato
  // OPPURE
  // 2. Sono sull'ultima riga
  // 
  
  const bool riporta = _forza_ariportare || 
    (!_gia_settato_ariportare && _cur->pos() < _cur->items()-1);
  
  if (riporta)  
  {
    dt = _tot_dare_progr  + _tot_dare_progr_ap;
    at = _tot_avere_progr + _tot_avere_progr_ap;
    dts = dt.string(TOT_PICTURE);
    ats = at.string(TOT_PICTURE);

    riga.format ("@b@%dg%s@%dg%c %s @%dg%c @%dg%s", 
                 _stampa_width == 132 ? SCRITTA : DARE198-STUMB,                          
                 (_nuovo_mese && !_forza_ariportare) ? "Totale progressivi generali    " : "A riportare                    ",
                 _stampa_width == 132 ? TOTDARE132  : DARE198,
                 'D',                   
                 (const char *) dts,    
                 _stampa_width == 132 ? SEZA132 : DARE198+20,
                 'A',                   
                 _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                 (const char *) ats);
    set_footer (r++, (const char*) riga);          
    
    _forza_ariportare = FALSE;
  }
} 


int CG3400_application::set_totali_pagina(int righe)
{
  TString           progr_dare_ap(22), progr_avere_ap(22);
  TString           progr_dare(22), progr_avere(22), dts(22), ats(22);
  TString256        riga;
  bool              ap = FALSE; 
  const int SHIFT  = 15;
  const int STUMB  = 51 + SHIFT;
  real              dt, at;
  int               r = righe == 0 ? 1 : righe;  
  
  if (_tot_avere_progr_ap != ZERO || _tot_dare_progr_ap != ZERO)
  {
    progr_dare_ap  = _tot_dare_progr_ap.string(TOT_PICTURE);
    progr_avere_ap = _tot_avere_progr_ap.string(TOT_PICTURE);
    ap = TRUE;
  }
  
  // SONO SULL'ULTIMO ???????????? SI O NO ????????????                   
  //  if (_cur->pos() >= _cur->items()-1)    // se sono sull'ultimo
  if (_cur->pos() == _cur->items()-1)    // se sono sull'ultimo
  {
    // I totali distinti tra anno precedente e corrente SOLO SE STAMPA DI PROVA
    if (!_stampa_definitiva)
    {  
      progr_dare  = _tot_dare_progr.string (TOT_PICTURE);
      progr_avere = _tot_avere_progr.string(TOT_PICTURE);  
      riga = "";        
      riga.format("@b@%dgTotale progressivi @%dg%c %s @%dg%c @%dg%s", 
                  _stampa_width == 132 ? SCRITTA : DARE198-STUMB,
                  _stampa_width == 132 ? TOTDARE132 : DARE198-2,
                  'D',
                  (const char *) progr_dare, 
                  _stampa_width == 132 ? SEZA132 : DARE198+20,                  
                  'A',
                  _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                  (const char *) progr_avere
                  );    

      set_row (r++, (const char*) riga);    
      
      if (ap)
      {
        riga.format("@b@%dgTotale progressivi anno precedente @%dg%c %s @%dg%c @%dg%s", 
                    _stampa_width == 132 ? SCRITTA : DARE198-STUMB,
                    _stampa_width == 132 ? TOTDARE132  : DARE198-2,
                    'D',
                    (const char *) progr_dare_ap, 
                    _stampa_width == 132 ? SEZA132 : DARE198+20,                    
                    'A',
                    _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                    (const char *) progr_avere_ap
                    );    
        set_row (r++, (const char*) riga);
      }
    }      // !stampa_definitiva
    
    _tot_dare_generale  = _tot_dare_progr  + _tot_dare_progr_ap;
    _tot_avere_generale = _tot_avere_progr + _tot_avere_progr_ap;
    dts = _tot_dare_generale.string (TOT_PICTURE);
    ats = _tot_avere_generale.string(TOT_PICTURE);
    
    riga.format("@b@%dgTotale progressivi generali @%dg%c %s @%dg%c @%dg%s", 
                _stampa_width == 132 ? SCRITTA : DARE198-STUMB,
                _stampa_width == 132 ? TOTDARE132 : DARE198-2,
                'D',
                (const char *) dts, 
                _stampa_width == 132 ? SEZA132 : DARE198+20,                
                'A',
                _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                (const char *) ats
                );    

    set_row (r++, (const char*) riga);          
  }
  else      // Non ancora totale generale
  { 
// Se il movimento ha righe che continuano nella pagina successiva
// "A riportare" viene stampato dalla preprocess_footer senno' qui

    _gia_settato_ariportare  = TRUE;
    
    dt = _tot_dare_progr  + _tot_dare_progr_ap;
    at = _tot_avere_progr + _tot_avere_progr_ap;
    dts = dt.string(TOT_PICTURE);
    ats = at.string(TOT_PICTURE);

// "Se il mese e' finito devo scrivere Totale progressivi generali
// invece che A riportare"

    riga.format ("@b@%dgTotale progressivi generali @%dg%c %s @%dg%c @%dg%s", 
                   _stampa_width == 132 ? SCRITTA : DARE198-STUMB,    
                   _stampa_width == 132 ? TOTDARE132  : DARE198-2,
                   'D',                   
                   (const char *) dts,  
                   _stampa_width == 132 ? SEZA132 : DARE198+20,                   
                   'A',                   
                   _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                   (const char *) ats);
    set_row (r++, (const char*) riga);          
  }      
  return r;
}

int CG3400_application::stampa_intestazione_ditta()
{
  int           r=1;
  TString256    intes;
  TString       riga(_stampa_width);

  get_dati_ditta();

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

  set_header (++r, "Ditta: %5ld %-.50s %.35s %.5s %.20s %.2s", 
              get_firm(),
              (const char *)_ragsoc, 
              (const char *)_viafis, (const char *)_cap, 
              (const char *)_comunefis, (const char *)_provfis); 

  if (_stampa_definitiva)  
    intes.format ("Partita iva %s @24gCodice fiscale %s", 
                  (const char*)_paiva, (const char*)_cofi, 
                  _stampa_width == 132 ? 102 : 168
                  );
  else  
    intes.format ("Partita iva %s @24gCodice fiscale %s @%dg%s @%dgData @>", 
                  (const char*)_paiva, (const char*)_cofi, 
                  _stampa_width == 132 ? 102 : 168,
                  "LIBRO DI PROVA",
                  _stampa_width == 132 ? 117 : 183
                  );

  set_header (++r, "%s", (const char*)intes);
  r++;
  return r;
}

int CG3400_application::set_headers()
{
  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 (_stampa_definitiva)                                         
    set_header(r++, "Codice libro: %s %s ",(const char *) _reg_cod, (const char *) _reg_descr);
  else
    set_header(r++, "Codice libro: %s %s @%dgdalla data: %s alla data: %s @%dgEsercizio: %04d",
               (const char *) _reg_cod, (const char *) _reg_descr,
               _stampa_width == 132 ? 69 : 135,
               (const char *) data_da,  (const char *) data_a, 
               _stampa_width == 132 ? 117 : 183,
               _ae
               );

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

  if (_libro_cronologico)
    set_header(r, "@59gCodice         Conto"); 

  if (!_stampa_definitiva) {
    if (_stampa_width == 132) {
      set_header(r++, "@131gS");    
      set_header(r, "@1gN.riga"); 
    }
    else {
      set_header(r++, "@197gS");    
      set_header(r, "@1gN.riga");       
    }
  }
  else
    if (_libro_cronologico) r++;    // NON LASCIARE RIGHE IN BIANCO!!
  
  //    set_header(r, "@6gCod.Causale@34gDescrizione operazione");
  set_header(r, "@8gDescrizione operazione@36gCausale");
  if (_libro_cronologico)
    //  POSCONTO    = 74;
    set_header(r, "@74gGeneralita' cliente/fornitore"); 
  else
    set_header(r, "@59gCodice         Conto"); 
  
  if (_stampa_width == 132)
    set_header(r, "@120gImporto");
  else
    set_header(r, "@161gDare @184gAvere");
  
  if (!_stampa_definitiva)          
    set_header(r, _stampa_width == 132 ? "@131gB" : "@197gB");
  
  r++;

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

  return r;
}

void CG3400_application::preprocess_header()
{
  int r      = _last_header + 1;
  int pag    = printer().getcurrentpage();
  TString256   riporto;
  real         riporto_dare, riporto_avere;

  _gia_settato_ariportare  = FALSE;

  if (pag > 0)   // Stampa riporti
  {
    riporto_dare  = _tot_dare_progr  + _tot_dare_progr_ap;
    riporto_avere = _tot_avere_progr + _tot_avere_progr_ap;

    // Non stampa nulla se ZERO SOLO SE DI PROVA <<<<<---------------------
    // Lascio una riga senno' vado a finire sull'intestazione
    if (!_stampa_definitiva)
      if (riporto_dare == ZERO && riporto_avere == ZERO)
      {
        set_header (r, "");
        return;
      }

    TString dare (riporto_dare.string (TOT_PICTURE));
    TString avere(riporto_avere.string(TOT_PICTURE));

    riporto.format("@b@%dgRiporto: @%dg%c %17s  @%dg%c@%dg%17s",  // prima erano %15s
                   _stampa_width == 132 ? SCRITTA : DARE198-11,
                   _stampa_width == 132 ? TOTDARE132 : DARE198,
                   _stampa_width == 132 ? 'D' : ' ',
                   (const char *) dare,       
                   _stampa_width == 132 ? SEZA132 : SEZA132,
                   _stampa_width == 132 ? 'A' : ' ',                   
                   _stampa_width == 132 ? TOTAVERE132 : AVERE198,
                   (const char *) avere 
                   );    

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

//
// 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)
{
  switch (file)
  {
  case LF_MOV:
    _nuovo_mese   = FALSE;    
    _iva_array.destroy();
    _nprog_mov   = _nprog_da;
    *_RecPartoDa = _cur->file(LF_MOV).curr();
    break;
  default:
    break;
  }
  return TRUE;
}

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

  if (yesno_box ("Interrompo la stampa ?"))
  {
  if (_stampa_definitiva) 
  aggiorna_tabreg (ultima_fatta, ultima_fatta);
  return TRUE;
  }
  else
  return FALSE;
  }
  ***/

void CG3400_application::fill_page(int start_riga, int righe_iva_settate)
{
  TString256   rigas;
  int rrr = start_riga;                            
  int r_l = printer().rows_left() - start_riga - righe_iva_settate;
  if (r_l < 0) 
  {                           
    // Tolgo l'intestazione + la riga con i riporti  
    r_l += printer().formlen() - (printer().headersize() + 1);
    _forza_ariportare = TRUE;
  }  

  // Se sono rimaste righe da riempire
  if (r_l > 0)
  {
    rigas.fill('=', _stampa_width);
    rigas.cut(_stampa_width+1);    
    //    sprintf(frm, "%%%3ds", _stampa_width);
    set_row(rrr++, "%s", (const char*) rigas);
    int j=0;
    // Calcola una specie di coefficiente angolare      
    int alfa = (_stampa_width - 6) / r_l;
    
    for ( ; r_l >= 1; r_l--)           // Non stampare sulla riga orizzontale!
    {
      rigas.format("@%dg======", j);
      set_row(rrr++, rigas);
      j += alfa;
    }
  }
}

print_action CG3400_application::postprocess_page(int file, int counter)
{
  int righe_iva_settate=0;
  bool        FINITO = FALSE;
  
  if (counter) 
  {
    if (_nuovo_mese) {
      if (!_stampa_definitiva)  // su bollato ho gia' barrato il foglio fino in fondo
        printer().formfeed();
      _nuovo_mese = FALSE;
    }
    return NEXT_PAGE;
  }

  switch (file)
  {
  case LF_MOV:

    reset_print();
    righe_iva_settate = 0;
    if (_libro_giornale_iva_unico)
    {
      righe_iva_settate = setta_righe_iva();
      righe_iva_settate = setta_righe_valuta(righe_iva_settate);
    }
    
    _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->pos() == _cur->items()-1)
    {
      _nuovo_mese = (_mese_succ != _mese_corr);
      int righe  = set_totali_giorno(_data_corr, righe_iva_settate);
      if (_nuovo_mese)
      {
        righe      = set_totali_pagina(righe);
        // Nella stampa su bollato metto un segno su tutte le righe 
        if (_stampa_definitiva)
          fill_page(righe, righe_iva_settate);
      }
      return REPEAT_PAGE;
    }

    if (righe_iva_settate > 0)
      return REPEAT_PAGE;
    
    break;

  case LF_RMOV:
    // Sposto qui per evitare di aggiornare i progressivi con una riga della
    // pagina dopo  
    update_totals(_sezione, _importo);
    break;
  default:
    break;
  }
  return NEXT_PAGE;
}

void CG3400_application::update_totals (char sezione, real& importo)
{
#ifdef DBG
  TString dgap(_tot_dare_gg_ap.string());
  TString dgpp(_tot_dare_progr_ap.string());  
  TString dgac(_tot_dare_gg.string());
  TString dgpc(_tot_dare_progr.string());
  TString agap(_tot_avere_gg_ap.string());
  TString agpp(_tot_avere_progr_ap.string());  
  TString agac(_tot_avere_gg.string());
  TString agpc(_tot_avere_progr.string());
#endif  

  if (sezione == 'D')
  {
    if (_annoEsMov != _ae)  {
      _tot_dare_gg_ap     += importo;    // prog. anno precedente
      _tot_dare_progr_ap  += importo;   
    }
    else  {
      _tot_dare_gg    += importo;    // prog. giornalieri
      _tot_dare_progr += importo;      // prog. generali
    }
  }
  else
  {                                   
    if (_annoEsMov != _ae)  {
      _tot_avere_gg_ap    += importo;
      _tot_avere_progr_ap += importo;
    }        
    else  {
      _tot_avere_gg    += importo;
      _tot_avere_progr += importo;
    }
  }
#ifdef DBG
  dgap = _tot_dare_gg_ap.string();
  dgpp = _tot_dare_progr_ap.string();  
  dgac = _tot_dare_gg.string();
  dgpc = _tot_dare_progr.string();
  agap = _tot_avere_gg_ap.string();
  agpp = _tot_avere_progr_ap.string();  
  agac = _tot_avere_gg.string();
  agpc = _tot_avere_progr.string();
#endif  
}    



void CG3400_application::set_rows (int file, int counter)
{
  TString16     datadoc_str, datareg_str, numdoc, frm, caus;
  TDate         datadoc, datareg;
  TString80     mov_descr, rmv_descr;
  TParagraph_string descr_conto("", 50);
  TContoOccas   tc;  
  long          numreg, protiva;
  int           r = 1;
  int           g, c;          
  long          s;
  static char   cf = ' ';
  static int    rdes = 1;
  
  switch (file)  
  {
  case LF_MOV:
    reset_row(1);
    reset_row(2);     
    
    datareg   = _cur->file(LF_MOV).get_date("DATAREG");        
    datadoc   = _cur->file(LF_MOV).get_date("DATADOC");        
    datareg_str = datareg.string();
    // "Fai vedere lo stesso ..-..-.... anche se non c'e' la data..."    
    if (datareg_str.empty())
      datareg_str = "  -  -    ";
    datadoc_str = datadoc.string();
    if (datadoc_str.empty())
      datadoc_str = "  -  -    ";    
    numdoc    = _cur->file(LF_MOV).get("NUMDOC");        
    numreg    = _cur->file(LF_MOV).get_long("NUMREG");        
    mov_descr = _cur->file(LF_MOV).get("DESCR");                    

    // Usati in setta_righe_iva per determinare tipo attivita'
    _reg       = _cur->file(LF_MOV).get(MOV_REG);  
    _anno_iva  = _cur->file(LF_MOV).get_int(MOV_ANNOIVA);

    protiva         = _cur->file(LF_MOV).get_long(MOV_PROTIVA);   
    caus            = _cur->file(LF_MOV).get(MOV_CODCAUS);  
    _occfpi         = _cur->file(LF_MOV).get(MOV_OCFPI);  
    _annoEsMov      = _cur->file(LF_MOV).get_int(MOV_ANNOES);
    _MovGiaStampato = _cur->file(LF_MOV).get_bool(MOV_STAMPATO);    
    
    if (_stampa_definitiva)                     
    {
      set_row(r,"Operazione n. @b%-7ld@r", _nprog_mov);
      set_row(r," del @b%s@r", (const char*)datareg_str); // XX/XX/XXXX
      set_row(r," doc. n. @b%-7s@r",(const char*)numdoc);
      set_row(r," del @b%s@r %-50s",(const char*)datadoc_str,
              (const char*)mov_descr);
    }
    else
    { 
      set_row(r,"Operazione n. @b%-7ld@r", numreg);
      set_row(r," del @b%s@r", (const char*) datareg_str);
      set_row(r," doc. n. @b%-7s@r", (const char*) numdoc);
      set_row(r," del @b%s@r %-50s", (const char*)datadoc_str,(const char*)mov_descr);
    }

    if (_annoEsMov != _ae)
      set_row(r," Comp. %04d", _annoEsMov);          
    
    if (_MovGiaStampato && !_stampa_definitiva)
      set_row(r,format("@%dg*",_stampa_width == 132 ? 131 : 197));

    if (caus.not_empty())
    {
      TString80 desc_caus(get_descr_caus(caus));
      set_row(r+1, "@36gCausale %3s %-50s", (const char*) caus, (const char*) desc_caus);
      if (_reg.not_empty())
        set_row(r+1, " (R.IVA @b%3s@r Prot. @b%ld@r) ", (const char*)_reg,protiva);
    } 

    break;
    
  case LF_RMOV:

    _num_rig++; 
    
    reset_print();
    
    g         = _cur->file(LF_RMOV).get_int("GRUPPO");      
    c         = _cur->file(LF_RMOV).get_int("CONTO");      
    s         = _cur->file(LF_RMOV).get_long("SOTTOCONTO");          
    cf        = _cur->file(LF_RMOV).get_char(RMV_TIPOC);    

    if (cf != 'C' && cf != 'F') 
      cf = ' ';
    
    numreg    = _cur->file(LF_RMOV).get_long("NUMREG");    
    datareg   = _cur->file(LF_RMOV).get("DATAREG");                  

    _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);

    r=1;

    // Num. progressivo di operazione. Azzerato in preprocess_page
    if (!_stampa_definitiva) set_row (r, "%7ld", _num_rig);

    set_row (r, "@8g%-50s", (const char*) rmv_descr);

    set_row (r, "@59g%03d.", g);
    if (c != 0)
      set_row (r, "%03d.",     c);
    if (s != 0L)
      set_row (r, "%06ld",     s);

    tc.set(g,c,s,cf,NULL,-1,_occfpi);

    if (_stampa_width == 132) 
      descr_conto.set_width (WCONTO132);      
    else                          // se a 198 non spezzo le descrizioni
      descr_conto.set_width(198);

    descr_conto = tc.descrizione();

    if (_stampa_width == 132)
      rdes = setta_righe_descr (descr_conto, conto);        
    else
    {
      rdes = 2;
      frm.format("@%dg%%-%ds", POSCONTO,50);
      set_row (r, frm, (const char*) descr_conto);
    }
    
    if (cf > ' ')
      if (_libro_cronologico)
        rdes = setta_righe_indirizzo(cf, s, rdes);    

    // NB Totali aggiornati in postprocess_page (update_totals())

    if (_stampa_width == 132)
    {
      set_row (r, "@110g%r", &_importo);  // prima era 110
      set_row (r, "@128g%c", _sezione);  
    }
    else  //  stampa_width == 198
      set_row (r, _sezione == 'D' ? "@152g%r" : "@174g%r", &_importo);  // il primo era 150
    
    if (_MovGiaStampato && !_stampa_definitiva)
      set_row(r,format("@%dg*",_stampa_width == 132 ? 131 : 197));

    break;

  default:
    break;
  }
}

//
// PREPROCESS_PAGE
//
// Non scarto nulla qui, non si deve mai vedere una stampa vuota
//
bool CG3400_application::preprocess_page(int file, int counter)
{
  if (counter) return TRUE;

  switch (file)  {
    
  case LF_MOV:
    _annoEsMov = _anno_iva = 0;    
    _iva_array.destroy();
    *_RecArrivoA = _cur->file(LF_MOV).curr();
    _nprog_mov++;           
// Il numero di operazione deve ripartire da 0 per ogni movimento    
    _num_rig = 0;
    _data_corr = _cur->file(LF_MOV).get_date(MOV_DATAREG);
// _ultima_data_mov finisce sul registro come ultima data di stampa
    if (_data_corr > _ultima_data_mov) _ultima_data_mov = _data_corr;
    _mese_corr = _data_corr.month();    
    break;

  case LF_RMOV: 
    break;

  case LF_RMOVIVA: 
    if (_libro_giornale_iva_unico)  calcola_iva ();
    break;

  default: 
    break;
  }
  set_rows (file, counter);
  return TRUE;
}

void CG3400_application::calcola_iva()
{
  TString  codiva;
  int      tipocr, tipodet, tipoatt;
  real     impo, impos;
  bool     intra;
  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);
    tipoatt = iva.get_int ("TIPOATT");
    codiva  = iva.get (RMI_CODIVA);
    intra   = iva.get_bool (RMI_INTRA);
    _iva_array.add_riga(impo,impos,ZERO,ZERO,codiva,tipodet,0,intra,tipoatt);
  }
}

int CG3400_application::setta_righe_descr(TParagraph_string& str, enum descr des)
{
  int           i = 1;
  TString16     frm;
  const char*   r;         
  //  char          descr[51];
  TString80     descr;
  
  switch (des)
  {
  case causale:    // lunga 20
    if (_libro_giornale_iva_unico)
      frm.format("@10g\0x25%ds", _stampa_width == 132 ? WCAUS132 : 40);
    else
      frm.format("@48g%%d", WCAUS132);
    break;
  case conto:     // lunga 21
    //    if (_libro_giornale_iva_unico)
    frm.format("@%dg%%-%ds", POSCONTO,WCONTO132);
    /*
       else
       frm.format("@26g%%d", POSCONTO,WCONTO132); */
    break;
  case operazione:  // lunga 28
    if (_libro_giornale_iva_unico)
      frm.format("@31g%%d", WOPER132);
    else
      frm.format("@69g%%d", WOPER132);
    break;
  default:
    break;
  }
  while ((r = str.get()) != NULL)  
  {
    descr = r;
    descr.ltrim();
    set_row (i++, (const char*)frm, (const char*)descr);
  }

  return i;
}

const char* CG3400_application::get_codiva_des(const char* codiva)
{
  _tabiva->zero();
  _tabiva->put("CODTAB", codiva);
  if (_tabiva->read() == NOERR)
    return _tabiva->get("S0");
  else
    return NULL;  
}

// 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;
  TString80 rig;

  for (j = 0; j < _iva_array.items(); j++)
  {
    TRigaiva& riga = (TRigaiva&)_iva_array[j];
    r = j+1;
    set_row(r, "   Imponibile@15g%r",    &riga._imponibile);
    set_row(r, "@31gImposta@39g%r",   &riga._imposta);
    //    set_row(r, "@58gCod.Iva@68g%3s", (const char*)riga._codiva);
    set_row(r, "@56gCod.Iva %3s", (const char*)riga._codiva);
    const TString80 codiva_des(get_codiva_des(riga._codiva));    
    const int       tipoatt = riga._tipoatt;
    if (_stampa_width == 132)
      set_row(r, "@68g%-.17s", (const char*)codiva_des);    
    else
      set_row(r, "@68g%-.50s", (const char*)codiva_des);    
    const int S132 = 89;      
    const int S198 = 119;      
    rig.format("@%dg", _stampa_width == 132 ? S132 : S198);    
    switch (riga._tipodet)
    {
    case 0 : 
      rig << "Detraibile             "; 
      break;
    case 1 : 
      rig << "Indetraibile su op.es. ";
      break;
    case 3 : 
      rig << "Passaggi interni       ";
      break;
    case 9 : 
      rig << "Indetraibile art.19    ";
      break;
    default: break;   
    } 
    set_row(r, (const char*)rig);

    TRegistro reg(_reg, _anno_iva);
    const bool att_mista_ev = reg.attivita_mista();
    if (tipoatt != 0 && att_mista_ev)
      set_row(r, " Tipo attivita' %d", tipoatt);
  } 
  _iva_array.destroy();
  return r; 
}

int CG3400_application::setta_righe_valuta(int riga)
{      
  TString16     codvali;
  real          corrval;
  int           r = riga;
  corrval   = current_cursor()->file(LF_MOV).get_real(MOV_CORRVALUTA);
  
  if (corrval != ZERO)
  {  
    codvali   = current_cursor()->file(LF_MOV).get(MOV_CODVALI);
    TString valut(corrval.string("###.###.###.###,@@"));
    r = riga+1;
    set_row(r,"@56gValuta %3s", (const char*)codvali);
    if (_stampa_width == 132)
      set_row(r,"@89gCorr.in valuta @109g%s", (const char*)valut);
    else
      set_row(r,"@119gCorr.in valuta @171g%s", (const char*)valut);
  }
  return r;  
}

// 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
int CG3400_application::setta_righe_indirizzo(char tipocf, long codcf,int rdes)
{
  TString16 prov, comcf, capcf, civcf, statocf;
  TString80 viacf, comune;
  bool      really_occas = FALSE;     
  char      tipoa;
  long      codanagr;    
  char      riga[256];
  int       r = rdes;
  
  _clifo->zero();
  _clifo->put(CLI_CODCF, codcf);
  _clifo->put(CLI_TIPOCF, tipocf);

  const bool clifo_ok = (_clifo->read() == NOERR);

  if (clifo_ok) really_occas = _clifo->get_bool(CLI_OCCAS);

  if (_occfpi.not_empty() && really_occas)   // => e' un occasionale...
  {
    TLocalisamfile occ(LF_OCCAS);
    
    occ.zero();
    occ.put(OCC_CFPI, _occfpi);
    if (occ.read() != NOERR) occ.zero();
    
    viacf = occ.get (OCC_INDIR);
    civcf = occ.get (OCC_CIV);
    capcf = occ.get (OCC_CAP);
    comcf = occ.get (OCC_COM);
  } 
else 
{
  // E' possibile cio' ?
  if (!clifo_ok) return r;

  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);
  tipoa   = _clifo->get_char(CLI_TIPOAPER);
  codanagr = _clifo->get_long(CLI_CODANAGPER);
}

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

if (viacf.not_empty())
{
  sprintf (riga, "@%dg%s %s",
           POSCONTO,
           (const char*) viacf,
           (const char*) civcf
           );

  set_row (r++, riga);
}

if (comune.not_empty() || prov.not_empty() || capcf.not_empty())
{
  sprintf (riga, "@%dg%s %s %s",
           POSCONTO,
           (const char*) capcf, (const char*) comune,
           (const char*) prov
           );
  set_row (r++, riga);  
}

// Se fisica prendo anche data nascita e luogo  
if (tipoa == 'F')
{
  TString80 comna;
  TString16 datana, codcomna, provna, capna, statona;
  
  datana = _clifo->get("DATANASC");
  
  if (datana.not_empty())
  {
    codcomna  = _clifo->get("COMNASC");
    TRectype dep = look_com (codcomna);

    comna     = dep.get(COM_DENCOM);
    provna    = dep.get(COM_PROVCOM);
    capna     = dep.get(COM_CAPCOM);
    
    statona   = dep.get("STATO");        
    
    sprintf (riga, "@%dg%s %s %s %s", POSCONTO,
             (const char*)datana,
             (const char*)comna,
             (const char*)provna, (const char*) capna);
    
    set_row(r++, riga);
  }
}
return r;
}

//
// 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 ("I8", (long)partito_da); // partito_da = -1 se stampa OK
    _tabreg->put ("I1", (long)_pagine_stampate + stampate); // pagine stampate
    _tabreg->put ("I6", _nprog_mov);    // ultimo numero di riga
    _tabreg->put ("R1", _tot_dare_generale);
    _tabreg->put ("R2", _tot_avere_generale);
    _tabreg->put ("D3", _ultima_data_mov);  // Data piu' alta trovata
    _tabreg->rewrite();
  }
}

void CG3400_application::get_date_aep(int aep, TDate* in, TDate* fin)
{
  TTable esc("ESC");
  
  esc.zero(); esc.put("CODTAB", format("%04d",aep));
  if (esc.read() == NOERR) 
  {
    *in  = esc.get_date("D0");
    *fin = esc.get_date("D1");
  }
}

const int es_prec(const int es_corr)
{
  TTable ese("ESC");
  TString16 first;
  TString   codtab;

  ese.first();  
  first = ese.get("CODTAB");
  
  codtab.format("%04d",es_corr);
  
  if (codtab == first)  
    return 0;
  
  return es_corr - 1;
}

bool CG3400_application::controlla_mov_aep()
{                  
  const int aep = es_prec(_ae);  
  bool gia_stampati = TRUE;
  TDate inizio_ep, fine_ep;

  if (aep == 0)   // = e' il primo esercizio
    return TRUE;
else
  get_date_aep(aep,&inizio_ep, &fine_ep);
  
#ifdef DBG
  TString instr(inizio_ep.string());  
  TString finstr(fine_ep.string());    
#endif

  TRectype da (_cur->file(LF_MOV).curr());
  TRectype a  (_cur->file(LF_MOV).curr());

  da.zero(); a.zero();
  da.put(MOV_DATAREG, inizio_ep);
  a.put (MOV_DATAREG, fine_ep);

  _cur->setregion(da, a);
  _cur->set_filterfunction(filter_func);
  //  _cur->setfilter(format("ANNOES=%04d && STAMPATO!=\"X\"", aep));

  (*_cur) = 0L;
  for ( ; _cur->pos() < _cur->items(); ++(*_cur))
  {
#ifdef DBG
    TString datareg(_cur->file().get("DATAREG"));  
    TString numreg(_cur->file().get("NUMREG"));  
#endif
    gia_stampati = _cur->file().get_bool("STAMPATO");  
    if (!gia_stampati) break;   // basta trovarne uno ancora da stampare
  }
  
  if (_cur->items() > 0L && !gia_stampati)
  {
    _cur->setfilter("");    
    warning_box("Impossibile proseguire nella stampa.\nEsistono movimenti nell'esercizio precedente non ancora stampati su bollato");
    return FALSE;
  }
  _cur->setfilter("");    
  return TRUE;
}

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

  _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("I8");
  _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");
  _stampa_stesso_registro = _tabreg->get_bool ("B8");
  _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;
}

void CG3400_application::set_reg_filter(TMask& m)
{
  TEdit_field& reg = m.efield(CODREG);
  reg.browse()->cursor()->set_filterfunction(filtra_reg);  
}

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

// NB
// Qui viene compilato app()._ae
// L'anno di esercizio e' determinato da DATA_A
//
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());                  
    TString16       dep(data_a.string());

    if (dep.empty()) return TRUE;                   
    
    const int       ae = date2esc(data_a); // Anno esercizio

    app()._ae = ae;
    if (ae == 0) 
      return f.error_box("La data specificata non appartiene a nessun esercizio");
    else                        
    {
      m.set(ANNO_ESER, ae);
      m.send_key(K_TAB, CODREG);
    }  
  }
  
  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);

    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");
      }
    }
  }  // 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))
  if (k == K_TAB)
  {
    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
//
// ----------->>>>  SCRIVO ANCHE QUI _ae <<<<----------------
//
bool CG3400_application::mask_a_cod_reg (TMask_field& f, KEY k)
{
  if (f.to_check(k))
  {
    TMask&              m = f.mask();
    CG3400_application& a = app();    
    const bool definitiva = m.get_bool(STAMPA_DEF);
    const TString16 data_astr(m.get(DATA_A));
    const TDate     data_a(m.get(DATA_A));

    // 25/11 controlli sul registro solo DOPO aver messo la DATA_A
    if (data_astr.empty()) 
      return TRUE;
    else
      a._ae = date2esc(data_a);  // Anno esercizio

    const TString16 reg_cod(f.get()); 

    if (reg_cod.empty())
    {
      if (k == K_TAB)   // Magari ci ripassa e lo inserisce
        return TRUE;
      else              // Se e' K_ENTER mi serve davvero
        return f.error_box("Manca il codice registro");
    }
    
    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, a._ae);
       */                           
  }
  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_SPACE) 
  {
    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);
    f.mask().set(PAGINA_DA,       a._pagine_stampate);
  }
  return TRUE; 
}

bool CG3400_application::mask_b_warning (TMask_field& f, KEY k)
{
  static bool gia_detto = FALSE;

  if (!gia_detto)
    if (k == K_SPACE)
    {
      f.warning_box("Le modifiche a questi progressivi saranno scritte nel registro");
      gia_detto = TRUE;
      return TRUE;
    }

  if (k == K_ENTER || k == K_ESC)
    gia_detto = FALSE;
  
  return TRUE;
}

void CG3400_application::init_print()
{
  // 17.5.95 Leggo parametri di stampa del registro  
  TString16   config;
  const long  codditta = get_firm();   
  const char* reg      = (const char*)_reg_cod;

  config.format("REG%05ld%03s", codditta, reg);

  printer().read_configuration(config);
  
  if (_stampa_len != 0) 
    printer().formlen(_stampa_len);

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

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

//  set_real_picture (REAL_PICTURE);
  set_real_picture (TOT_PICTURE);
  set_print_zero(TRUE);

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

  // Solo se _pagina_da diversa da 0
  if (_pagina_da)  
    printer().set_from_page (_pagina_da - _pagine_stampate);

  // la stampa precedente era andata male  
  //  if (_stampa_ok != -1) set_page_number (_stampa_ok); 
  
  _last_header = set_headers();
}

void CG3400_application::init_totals()
{
  _tot_dare_gg_ap     = ZERO;
  _tot_avere_gg_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;
  if (_stampa_definitiva)
  {
    _tot_dare_progr     = _tot_dare;
    _tot_avere_progr    = _tot_avere;
  }
  else
  {
    _tot_dare_progr     = ZERO;
    _tot_avere_progr    = ZERO;
  }
}

bool CG3400_application::init_cursor()
{   
  bool gia_stampati = FALSE;
  
  TRectype da (_cur->file(LF_MOV).curr());
  TRectype a  (_cur->file(LF_MOV).curr());

#ifdef DBG
  TString instr(_data_da.string());  
  TString finstr(_data_a.string());    
#endif                  

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

  _cur->setregion(da, a);
  _cur->set_filterfunction(filter_func);

  _cur->setfilter(_stampa_definitiva ? "STAMPATO!=\"X\"" : "");
  
  (*_cur) = 0L;

  if (_cur->items() == 0L)
  {
    _cur->setfilter("");  
    return warning_box ("Non ci sono movimenti da stampare nel periodo selezionato.\nLa stampa e' annullata");
  }

  return TRUE;
}

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);
  //  set_reg_filter(ma);

  _pagina_da    = 0;  // Parto dall'inizio
  _forza_ariportare = FALSE;

  while ((tasto = ma.run()) != K_QUIT)
  {
    _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);

    _stampa_width      = ma.get_int(STAMPA_WIDTH);
    _stampa_len        = ma.get_int(STAMPA_LEN);

    // Se stampa definitiva DALLA_DATA e' la data di inizio esercizio
    // e si scartano i movimenti gia' stampati su bollato
    if (_stampa_definitiva) 
    {
      _data_da = _inizioEs;

      // Controlla che non siano rimasti movimenti ancora da stampare dell'es.prec.
      if (_stampa_stesso_registro) 
        if (!controlla_mov_aep()) 
          continue;
    }
    
    if (!init_cursor()) continue;
    
    if (_stampa_definitiva)
    {
      TMask mb("cg3400b");
      mb.set_handler (DLG_RIPRISTINA, mask_b_ripristina);
      mb.set_handler (PROGR_DARE,     mask_b_warning);
      mb.set_handler (N_RIGA_STAMPATO,mask_b_warning);      
      mb.set_handler (ULTIMA_DATA,    mask_b_warning);
      mb.set (PROGR_DARE,      _tot_dare.string());
      mb.set (N_RIGA_STAMPATO, _nprog_da);
      mb.set (ULTIMA_DATA,     _last_data.string());
      mb.set (PAGINA_DA,       _pagine_stampate);

      tasto = mb.run();           
      if (tasto == K_ENTER) 
      {
        _nprog_da  = mb.get_long(N_RIGA_STAMPATO);
        _last_data = mb.get(ULTIMA_DATA);
        real dare2(mb.get(PROGR_DARE));
        _pagina_da = mb.get_int(PAGINA_DA);
        // "Se l'utente cambia il progressivo dare, esso viene uguagliato all'avere"        
        if (dare2 != _tot_dare)
        {
          _tot_dare     = dare2;
          _tot_avere    = dare2;
        }
      }
      else
        continue;
    }

    init_print();
    init_totals();

    return TRUE;
  }
  return FALSE;
}

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

