#include <config.h>
#include <printapp.h>

#include "../cg/cgsaldac.h"
#include "sc2.h"
#include "sc2201.h"    
#include "sc2300.h"    

#include <clifo.h> 
#include <nditte.h>
#include <pconti.h>

///////////////////////////////////////////////////////////
// Stampa scaduto
///////////////////////////////////////////////////////////

enum tipo_st {nessuno=0, tutti=1, clienti=2, fornitori=3, altri=4};

const char * scaglioni[9] = 
             {"0 gg","+15 gg","+30 gg","+45 gg","+60 gg","+30 gg","+60 gg","+90 gg","+120 gg"};

struct _LineTotal : public TObject  //Oggetto di base per i TAssoc_array dei totali
{                                     
  real _rd, // Residuo documento
       _ns, // Non scaduto
       _bf, // In attesa buon fine
       _s1, // Scaglione 1 
       _s2, // Scaglione 2 
       _s3, // Scaglione 3 
       _s4, // Scaglione 4 
       _s5, // Scaglione 5 
       _s6, // Scaglione 6 
       _s7; // scaglione 7
  virtual TObject* dup() const { return new _LineTotal(*this); }
  _LineTotal() {_rd = 0.0; _ns = 0.0; _bf = 0.0; _s1 = 0.0;
                _s2 = 0.0; _s3 = 0.0; _s4 = 0.0; _s5 = 0.0; _s6 = 0.0; _s7 = 0.0;}
};

class TStampaScaduto : public TPrintapp
{ 
  TRelation     *_rel1, *_rel2;                          // Relazioni di lavoro...
  int           _cur1, _cur2,                            // Identificatori dei cursori di lavoro... 
                _cur3, _cur4;
  
  TSelection_ext_mask *_m;
  
  TLocalisamfile *_scad,*_pagsca;
  tipo_st   _tipost;                                     // Tipo di stampa impostato
  bool      _end_printed,
            _stvaluta,
            _pending_clifo,
            _ordcod;                                     // VERO=ordine per codice, FALSO=ordine per ragione sociale
  TString   _anno,_numdoc,_protiva,_datadoc,_codval,_residuo,
            _nonscad,_buonfin,_sc_1,_sc_2,_sc_3,_sc_4,_sc_5,
            _sc_6, _sc_7, _cod, _cod_pre, _des;
  TDate     _limop, _limscad, _datas, _limbf;            // Data limite operazione, data limite scaduto e data di stampa
  int       _gcr;                                        // Giorni per Calcolo Rischio (valido solo per stampa clienti)
  real      _unsnc,_uns;                                 // Unassigned per partita.
  TArray    _t,                                          // Array per i totali
            _s_date;                                     // Date per lo scaduto
  
  static TString _last_game;
  static bool fil_function(const TRelation *);

public:             
  virtual bool preprocess_page(int file, int counter);          
  virtual bool preprocess_print(int file, int counter);         
  virtual print_action postprocess_print(int file, int counter);
  virtual print_action postprocess_page(int file, int counter); 
  virtual void preprocess_header() {};                          
  virtual bool user_create();                                   
  virtual bool user_destroy();                                  
  virtual bool set_print(int);
  void set_page_clifoco(int& nriga);
  void set_page_part(int& nriga);
  virtual void set_page (int file, int counter);
  void print_totali_rows(int& nriga, bool what);
  void print_totali(int& nriga);
  void print_header();
  void update_totals(bool what,real& res,real& non,real& buo,
                     real& s1,real& s2,real& s3,real& s4,real& s5, real& s6, real& s7);
  void compute_unassigned(TPartita& p);
  void compute_all(TPartita& p, TBill& bill);
  TStampaScaduto();
};

TString TStampaScaduto::_last_game;
                  
inline TStampaScaduto& app() {return (TStampaScaduto&)main_app();}

bool TStampaScaduto::fil_function(const TRelation *r)
{
  TRectype& part = r->curr(LF_PARTITE);
  
  TString80 key;
  key.format("%03d%03d%06ld%4d",
             part.get_int(PART_GRUPPO), part.get_int(PART_CONTO), 
             part.get_long(PART_SOTTOCONTO), part.get_int(PART_ANNO));
  key << part.get(PART_NUMPART);           
  
  const bool rt = key != _last_game;
  if (rt)
    _last_game = key;
  return rt;
}

void TStampaScaduto::update_totals(bool what, real& res, real& non, real& buo,
                                   real& s1, real& s2, real& s3, real& s4, real& s5,
                                   real& s6, real& s7) 
{
  TAssoc_array& a = (TAssoc_array&) _t[what];
  const bool is_key = a.is_key(_codval);
  _LineTotal l;
  _LineTotal& ll = (is_key ? (_LineTotal&)a[_codval] : l);
  ll._rd += res;
  ll._ns += non; 
  ll._bf += buo;
  ll._s1 += s1; 
  ll._s2 += s2;
  ll._s3 += s3;
  ll._s4 += s4;
  ll._s5 += s5;
  ll._s6 += s6;
  ll._s7 += s7;
  a.add(_codval,ll,is_key);
}                                      

void TStampaScaduto::compute_unassigned(TPartita& p)
{  
  TRecord_array& ra = p.unassigned();
  
  _uns = 0.0; _unsnc = 0.0;
  for (int r = ra.last_row(); r > 0; r = ra.pred_row(r))
  {     
    const TRectype& rec = ra.row(r);
    const TRiga_partite& sum = p.riga(rec.get_int(PAGSCA_NRIGP));
    const char * field = (_stvaluta && sum.in_valuta() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO);
    if (sum.get_int(PART_TIPOMOV) == 2) // Is it a credit note ?
      _unsnc += rec.get_real(field);
    else
      _uns += rec.get_real(field);
  }    
}

void TStampaScaduto::compute_all(TPartita& p, TBill& bill)
{ 
  real residuo,nonscad,buonf,s1,s2,s3,s4,s5,s6,s7,res_pagati;
  residuo = 0.0; nonscad = 0.0; buonf = 0.0; s1 = 0.0; 
  s2 = 0.0; s3 = 0.0; s4 = 0.0; s5 = 0.0; s6 = 0.0; s7 = 0.0;    
  res_pagati = 0.0;
  compute_unassigned(p);
  for (int r = p.last(); r > 0; r = p.pred(r)) // Browse all rows (partite)
  {
    TRiga_partite& rp = p.riga(r);
    // se la data di registrazione della partita ' > di _limop (data lim operazione)
    // non deve scorrere le scadenze
    TDate data_reg(rp.get_date(PART_DATAREG));
    if (data_reg > _limop) continue;
    for (int n=rp.rate(); n > 0; n--) // Browse all rows (scadenze)
    {  
      TRiga_scadenze& rs = rp.rata(n);
      TDate d(rs.get_date(SCAD_DATASCAD));
      const char* field  = (_stvaluta && rs.in_valuta()) ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
      const char* sfield = (_stvaluta && rs.in_valuta()) ? SCAD_IMPORTOVAL : SCAD_IMPORTO;
      const char ssez = rp.sezione();
      TImporto scd,pag,bf,work_imp;
      scd += TImporto(ssez,rs.get_real(sfield)); // Importo in scadenza...
      pag += rs.importo_pagato(_stvaluta);     // Quanto e' stato pagato per questa scadenza?
      
      // Scorre le righe di pagamento per trovare la riga corripondente alla prima data pagamento
      // di questa rata. Motivo: il primo pagamento delle rata corrente, effettuato tramite effetto
      // (ai fini del calcolo B.F.) deve essere considerato con la data scadenza
      const int lst = rs.last();
      int prima_riga_pagamento = -1;
      TDate first_date;// data relativa alla prima riga di pagamento
      for (int pp = rs.first(); pp <= lst; pp = rs.succ(pp))
      {
        const TRiga_partite& sum = p.riga(pp);
        TDate current_date(sum.get_date(PART_DATAPAG)); 
        int tipo_pag = rs.get_int(SCAD_TIPOPAG);
        if (tipo_pag>=2 && tipo_pag<=7) //Incasso tramite effetto
          if (prima_riga_pagamento==-1 || first_date > current_date)
          {
            first_date = current_date; 
            prima_riga_pagamento = pp;
          }
      }
      for (pp = rs.first(); pp <= lst; pp = rs.succ(pp)) // Browse all rows (pagamenti)
      {
        const TRectype pg = rs.row(pp);  
        const TRiga_partite& sum = p.riga(pp);
        const char sez = sum.sezione();
        const int tipomov  = sum.get_int(PART_TIPOMOV);
        // se tipomov e' 2 (Nota di credito assegnata)
        // storna da scdz. In entrambi i casi si ha l'operatore +=, perche' nel TImporto e' gia'
        // compresa la sezione opposta
        if (tipomov==2)
        {
          work_imp = TImporto(sez,pg.get_real(field));
          scd += work_imp;
          pag -= work_imp;
        }
        if ((tipomov==3 || tipomov==5) && _tipost==clienti && _gcr!=0)
        {
          TDate data_pag(sum.get_date(PART_DATAPAG));
          int tipo_pag = rs.get_int(SCAD_TIPOPAG);
          if (tipo_pag>=2 && tipo_pag<=7 && data_pag.ok()) //Incasso tramite effetto
          {
            if (prima_riga_pagamento > -1 && prima_riga_pagamento == pp)
              data_pag = d;    // Se e' il primo pagamento(in ordine di data) di questa rata
                               // prende la data di scadenza relativa.
            if (data_pag >= _limbf) // && data_pag <= _limscad)
              bf += TImporto(sez,pg.get_real(field));
          }
        }
      }          
      char norm='D';  
      if (_tipost == fornitori) 
        norm = 'A';
      else
        if (_tipost == altri && bill.find())
          norm = bill.sezione();
      pag.normalize((norm=='D') ? 'A' : 'D'); scd.normalize(norm); bf.normalize((norm=='D') ? 'A' : 'D');
      real res,a,b; a = pag.valore(); b = scd.valore(); buonf += bf.valore();
      res = b - a;
      if (_uns > 0.0)  // Rettifica i pagamenti con i non assegnati (calcolo sul residuo: scadenza-pagamento)
      {
        real gap = (_uns > res ? res : _uns); // questo e' quanto manca per completare questa scadenza
        a += gap;
        _uns -= gap; // aggiorna la cache..
      }
      if (_unsnc > 0.0) // Rettifica le scadenze con le N.C non assegnate.
      {
        real gap = (_unsnc > b ? b : _unsnc);
        b -= gap;
        _unsnc -= gap;
      }
      res = b - a;  // Scadenze - pagati = scaduto per questo gruppo di rate
      if (b == 0.0) // Se le scadenze sono a zero, vuol dire che sono state stornate
        res = 0.0;  // da qualche nota di credito o non assegnato  percio' non si ha residuo

      if (res < 0.0)  // Significa che l'importo pagato e' maggiore dell'importo in scadenza
      {               // c'e' un residuo positivo, e quindi va memorizzato
        res *= -1.0;      // cambia il segno
        res_pagati+= res; // Residui pagati in piu'
        res = 0.0;
      }
      if (d > _limscad)
        nonscad += res;    
      else
      {
        // Detrae dal residuo scaduto eventuali pagamenti in piu' effettuati
        real gap = (res_pagati > res ? res : res_pagati);
        res -= gap;
        res_pagati -= gap;
      }
      if (d <= _limscad && d >= (TDate&)_s_date[0])
        s1 += res;
      if (d < (TDate&)_s_date[0] && d >= (TDate&)_s_date[1])
        s2 += res;
      if (d < (TDate&)_s_date[1] && d >= (TDate&)_s_date[2])
        s3 += res;
      if (d < (TDate&)_s_date[2] && d >= (TDate&)_s_date[3])
        s4 += res;
      if (_tipost == fornitori) 
      {
        if (d < (TDate&)_s_date[3] && d >= (TDate&)_s_date[4])
          s5 += res;
        if (d < (TDate&)_s_date[4] && d >= (TDate&)_s_date[5])
          s6 += res;
        if (d < (TDate&)_s_date[5])
          s7 += res;
      }
      else 
      {
        if (d < (TDate&)_s_date[3])
          s5 += res;  
      }
      residuo += res;
    }
  }
  if (residuo != 0.0)
  {
    if (_stvaluta && _codval != "   ") _residuo = residuo.string(".3");
    else _residuo = residuo.string(".");
  }
  if (nonscad != 0.0)
  {
    if (_stvaluta && _codval != "   ") _nonscad = nonscad.string(".3");
    else _nonscad = nonscad.string(".");
  }
  if (buonf != 0.0)
  {
    if (_stvaluta && _codval != "   ") _buonfin = buonf.string(".3");
    else _buonfin = buonf.string(".");
  }
  if (s1 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_1 = s1.string(".3");
    else _sc_1 = s1.string(".");
  }
  if (s2 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_2 = s2.string(".3");
    else _sc_2 = s2.string(".");
  }
  if (s3 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_3 = s3.string(".3");
    else _sc_3 = s3.string(".");
  }
  if (s4 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_4 = s4.string(".3");
    else _sc_4 = s4.string(".");
  }
  if (s5 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_5 = s5.string(".3");
    else _sc_5 = s5.string(".");
  }
  if (s6 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_6 = s6.string(".3");
    else _sc_6 = s6.string(".");
  }
  if (s7 != 0.0)
  {
    if (_stvaluta && _codval != "   ") _sc_7 = s7.string(".3");
    else _sc_7 = s7.string(".");
  }
  // Aggiorna i totali... 
  if (residuo!=0.0 || nonscad!=0.0 || buonf!=0.0 || s1!=0.0 || s2!=0.0 || s3!=0.0 || s4!= 0.0 || s5!= 0.0 || s6!=0.0 || s7!=0.0)
  {
    update_totals(0, residuo, nonscad, buonf, s1, s2, s3, s4, s5, s6, s7); // Singolo...
    update_totals(1, residuo, nonscad, buonf, s1, s2, s3, s4, s5, s6, s7); // ...Generale
  }
}

bool TStampaScaduto::preprocess_page(int file, int counter)
{   
  if (file == LF_PARTITE)
  { 
    const TRectype& curr = current_cursor()->curr(file);
  
    TBill bill(curr);
    const bool checked = _m->selected(bill);

    if (!checked && !_end_printed) // Se non e' stato selezionato salta al prossimo record
      return FALSE;
    
    int nriga = 1;
    if (_tipost == clienti || _tipost == fornitori)
    {            
      const TRectype& clifo = current_cursor()->curr(LF_CLIFO);
      _des = clifo.get(CLI_RAGSOC);
      _cod = clifo.get(CLI_CODCF);
    }
    else 
    {
      const TRectype& pcon = current_cursor()->curr(LF_PCON);
      _des = pcon.get(PCN_DESCR);
      _cod = pcon.get(PCN_GRUPPO);
      _cod << "  " << pcon.get(PCN_CONTO); 
      _cod << "  " << pcon.get(PCN_SOTTOCONTO);
    }                                 
    
    if (_cod != _cod_pre || _end_printed) // Controlla se e' cambiato il codice cli/fo/conto
    {
      reset_print();
      if (_cod_pre != "") // stampa i totali del precedente solo se non e' la prima
      {
        TAssoc_array& sin_tot = (TAssoc_array&) _t[0];
        if (sin_tot.items() > 0)
          print_totali(nriga); 
          
        if (_end_printed) 
        {
          TAssoc_array& gen_tot = (TAssoc_array&) _t[1];
          if (gen_tot.items() > 0)
          {
            set_row(nriga,"TOTALE GENERALE");
            print_totali_rows(nriga,1);
          }
          return TRUE; // Go back, print and exit!
        }
      }
      _cod_pre = _cod;
      _pending_clifo = TRUE;   
    }

    if (curr.empty()) // Attenzione: Possono succedere anche queste cose!
      return FALSE;             
    TPartita p(curr);

    //Pesca gli estremi dalla prima riga di fattura, che non e' necessariamente la riga #1
    const int r = p.prima_fattura();
    if (r <= 0) 
      return TRUE;             // se non ci sono fatture ... salta al prossimo

    _residuo = "";
    _nonscad = ""; 
    _buonfin = "";
    _sc_1 = "";
    _sc_2 = "";
    _sc_3 = "";
    _sc_4 = "";
    _sc_5 = "";
    _sc_6 = "";
    _sc_7 = "";
    
    if (r > 0)  //Skip next partita if no fatture!
    {
      TRiga_partite& rp = p.riga(r);
      _anno = rp.get(PART_ANNO);
      _anno.ltrim(2);       
      _numdoc = rp.get(PART_NUMDOC);
      _protiva = rp.get(PART_PROTIVA);
      _datadoc = (const char*) rp.get_date(PART_DATADOC);
      _codval  = (_stvaluta ? rp.get(PART_CODVAL): "");
      if (_codval.empty()) _codval = "   ";
      // Now performing fulkrum...
      compute_all(p, bill);
    }
    
    current_cursor()->repos(); // Very, very necessary...
    
    // Se c'e' qualcosa da stampare (ovvero almeno un importo non nullo)
    const bool to_print = !_residuo.empty() || !_nonscad.empty() || !_sc_1.empty() || !_sc_2.empty() ||
          !_sc_3.empty() || !_sc_4.empty() || !_sc_5.empty() || !_sc_6.empty() || !_sc_7.empty() || 
          (_tipost == clienti && !_buonfin.empty());
    if (to_print)
    {
      if (curr.get_int(PART_NRIGA) == 1)
      {
        if (_pending_clifo)
        {
          set_page_clifoco(nriga);  // Setta le righe per stampare le informazioni del cli/fo/conto
          set_row(++nriga,""); 
          nriga++;  
          _pending_clifo = FALSE;
        }
        set_page_part(nriga);
      }
    }
  }
  return TRUE;
}

bool TStampaScaduto::preprocess_print(int file, int counter)
{ 
  return TRUE;
}
              
print_action TStampaScaduto::postprocess_print(int file, int counter)
{  
  print_action rt = NEXT_PAGE;            
  if (!_end_printed)
    if ((file == LF_PARTITE))
    {             
      rt = REPEAT_PAGE;
      _end_printed = TRUE;
    }
  return rt;
}

print_action TStampaScaduto::postprocess_page(int file, int counter)
{   
  return NEXT_PAGE;
}

bool TStampaScaduto::user_create()
{                                                
  _rel1 = new TRelation(LF_PARTITE);
  _rel1->add(LF_CLIFO,"TIPOCF=TIPOC|CODCF=SOTTOCONTO",1);
//  _cur1 = add_cursor(new TSorted_cursor(_rel1,"SOTTOCONTO|ANNO|NUMPART","",1)); 
  _cur1 = add_cursor(new TCursor(_rel1)); 
  _cur2 = add_cursor(new TSorted_cursor(_rel1,"UPPER(20->RAGSOC)|ANNO|NUMPART","",1));
  
  _rel2 = new TRelation(LF_PARTITE);           
  _rel2->add(LF_PCON,"GRUPPO=GRUPPO|CONTO=CONTO|SOTTOCONTO=SOTTOCONTO",1);
//  _cur3 = add_cursor(new TSorted_cursor(_rel2,"GRUPPO|CONTO|SOTTOCONTO|ANNO|NUMPART","",1)); 
  _cur3 = add_cursor(new TCursor(_rel2));
  _cur4 = add_cursor(new TSorted_cursor(_rel2,"UPPER(19->DESCR)|ANNO|NUMPART","",1)); 
  
  _scad = new TLocalisamfile(LF_SCADENZE);
  _pagsca = new TLocalisamfile(LF_PAGSCA);
  _t.add(new TAssoc_array);_t.add(new TAssoc_array);
  for (int i = 0; i < 6; i++)
    _s_date.add(new TDate);
  
  TConfig conf (CONFIG_DITTA,"cg");
  _m = new TSelection_ext_mask("sc2300a");
  _m->enable(F_VALUTA,conf.get_bool("GesVal")); 

  enable_print_menu();               
  return TRUE;
}

bool TStampaScaduto::user_destroy()
{
  if (_rel1)  delete _rel1;
  if (_rel2)  delete _rel2;
  if (_scad)     delete _scad;
  if (_pagsca)   delete _pagsca;
  if (_m) delete _m;
  _t.destroy();
  _s_date.destroy();
  return TRUE;
}

bool TStampaScaduto::set_print(int)
{ 
  const bool rt = _m->run() == K_ENTER;
  if (rt)  
  {
    reset_files();
    reset_print();
    
    if (_m->get_who() == 'P') 
    {
      _tipost = altri;
    }  
    else
    {
      if (_m->get_who() == 'C') _tipost = clienti;
      else _tipost = fornitori;
    }  
    if (_m->get_key() == 1) _ordcod = TRUE;
    else _ordcod = FALSE;
    _end_printed = _pending_clifo = FALSE;
    _gcr      = _m->get_int(F_GIORNI);
    _stvaluta = _m->get_bool(F_VALUTA);
    _datas    = (const char *)(_m->get(F_DATASTAMPA));
    _limop    = (const char *)(_m->get(F_DATAOPERAZIONE));
    _limscad  = (const char *)(_m->get(F_DATASCADUTO));
    _limbf = _limscad - (long)_gcr; // Limite inferiore per le scadenze a Buon Fine.
    _anno.cut(0);_numdoc.cut(0);_protiva.cut(0);_datadoc.cut(0);
    _codval.cut(0);_residuo.cut(0);_nonscad.cut(0);_buonfin.cut(0);
    _cod.cut(0); _des.cut(0); _cod_pre.cut(0);
    _sc_1.cut(0);_sc_2.cut(0);_sc_3.cut(0);_sc_4.cut(0);_sc_5.cut(0);_sc_6.cut(0);_sc_7.cut(0);
    for (int it=0; it < _t.items(); it++)
    {
      TAssoc_array& aa = (TAssoc_array&) _t[it];
      aa.destroy();  // Totali lineari (singolo e generale)
    }

    get_cursor(_cur1)->set_filterfunction(fil_function,TRUE);
    get_cursor(_cur2)->set_filterfunction(fil_function,TRUE); 
    get_cursor(_cur3)->set_filterfunction(fil_function,TRUE); 
    get_cursor(_cur4)->set_filterfunction(fil_function,TRUE); 
    _last_game.cut(0);
    
    TRectype filter_from(LF_PARTITE), filter_to(LF_PARTITE);

    switch (_tipost)
    {       
     case clienti:
     case fornitori:
       filter_from.put("TIPOC", _tipost == clienti ? "C" : "F");
       filter_to = filter_from;
       if (_ordcod) // Per codice...
       {
         select_cursor(_cur1);
         get_cursor(_cur1)->setregion(filter_from, filter_to);
       }
       else     // ... e ragione sociale
       {
         select_cursor(_cur2);
         get_cursor(_cur2)->setregion(filter_from, filter_to);
       }
       add_file(LF_PARTITE);
       add_file(LF_CLIFO,LF_PARTITE);
       break;
     case altri:
       filter_to.put("TIPOC", "A");   // Sporco trucco per selezionare solo i conti
       if (_ordcod) // Per codice...
       {
         select_cursor(_cur3);
         get_cursor(_cur3)->setregion(filter_from, filter_to); // Filtro per i conti normali!
       }
       else         // ... e descrizione
       {
         select_cursor(_cur4);
         get_cursor(_cur4)->setregion(filter_from, filter_to); // Filtro per i conti normali!
       }
       add_file(LF_PARTITE);
       add_file(LF_PCON,LF_PARTITE);
       break;
     default: break;
    } // End of inner switch

    long inc = 30l;
    if (_tipost == fornitori)
      inc = 15l;
    long nday = inc;
    for (int j = 0; j < 6; j++)
    {
      TDate* d = (TDate *)_s_date.objptr(j);
      if (_tipost == fornitori && (j == 4 || j == 5) )
        nday += inc;
      *d = _limscad - nday;
      nday += inc;
    }
  }  // End if
  return rt;
}

void TStampaScaduto::print_totali_rows(int& nriga, bool what)
// If what is 0 prints single total... else prints also general total
{
  TAssoc_array& xassoc = (TAssoc_array&) _t[what];
  TString_array as;
  const int items = xassoc.items();
  xassoc.get_keys(as);
  as.sort();
  for (int i=0; i < items; i++)
  {
    TString k(as.row(i)); // Chiave di ordinamento(valuta)
    TString value;
    _LineTotal& v = (_LineTotal&)xassoc[k];
    if (k != "   ")
      set_row(nriga,"@37g%-3s",(const char*)k);
    if (_stvaluta && k != "   ") value = v._rd.string(".3");
    else value = v._rd.string(".");
    if (v._rd != 0.0)
      set_row(nriga,"@41g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._ns.string(".3");
    else value = v._ns.string(".");
    if (v._ns != 0.0)
      set_row(nriga,"@60g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._bf.string(".3");
    else value = v._bf.string(".");
    if (v._bf != 0.0)
      set_row(nriga,"@79g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s1.string(".3");
    else value = v._s1.string(".");
    if (v._s1 != 0.0)
      set_row(nriga,"@98g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s2.string(".3");
    else value = v._s2.string(".");
    if (v._s2 != 0.0)
      set_row(nriga,"@117g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s3.string(".3");
    else value = v._s3.string(".");
    if (v._s3 != 0.0)
      set_row(nriga,"@136g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s4.string(".3");
    else value = v._s4.string(".");
    if (v._s4 != 0.0)
      set_row(nriga,"@155g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s5.string(".3");
    else value = v._s5.string(".");
    if (v._s5 != 0.0)
      set_row(nriga,"@174g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s6.string(".3");
    else value = v._s6.string(".");
    if (v._s6 != 0.0)
      set_row(nriga,"@193g%18s",(const char*) value);
    if (_stvaluta && k != "   ") value = v._s7.string(".3");
    else value = v._s7.string(".");
    if (v._s7 != 0.0)
      set_row(nriga,"@212g%18s",(const char*) value);
    set_row(++nriga,"");                           
  } 
  xassoc.destroy(); // Distrugge il totale appena stampato 
}
                    
void TStampaScaduto::print_totali(int& nriga)
{ 
  TString s("CLIENTE");
  
  if (_tipost == fornitori) s = "FORNITORE";
  else if (_tipost == altri) s = "CONTO";
  reset_row(nriga);
  set_row(nriga++,"");
  reset_row(nriga);
  set_row(nriga,"TOTALE %s",(const char*) s);
  print_totali_rows(nriga,0);
  set_row(++nriga,"");
  nriga++;
}

void TStampaScaduto::print_header()
// Setta le righe dell'intestazione
{
  int soh = 1;    
  const long firm = get_firm();
  TString rw(230);

  reset_header ();
  TLocalisamfile ditte(LF_NDITTE);
  ditte.zero();
  ditte.put(NDT_CODDITTA, firm);
  ditte.read();
  if (ditte.bad()) ditte.zero();

  TString s;
  s = ditte.get(NDT_RAGSOC);    
  TString datas   = _datas.string();
  TString limop   = _limop.string();
  TString limscad = _limscad.string();

  set_header (soh++, "Ditta : %ld %s@158gData@163g%s @190gPag. @#",
             firm,  (const char *)s,  (const char *)datas);
             
  switch (_tipost)
  {
   case fornitori:
   case clienti:    
   {                           
    TString s1,s2, s3;
    int o = 0; // Offset per scaglioni.
    if (_tipost==fornitori)   
    {  
     set_header(soh++,"@72g** SCADUTO FORNITORI **");
     s1 = ""; s2 =  scaglioni[7]; // +90 gg per fornitori 
     s3 = scaglioni[8]; // +120 gg per fornitori
    }
    else                   
    {
     set_header(soh++,"@73g** SCADUTO CLIENTI **");
     s1 ="In Attesa B.F."; s2 = ""; s3 = "";
     o = 4;
    }
    set_header (soh++,"@73gAl %s Operazioni al %s",(const char*)limscad, (const char*)limop);
    rw.fill('-');
    set_header(soh++, (const char *) rw);                          
    set_header(soh++,"CODICE@18gC O G N O M E    E     N O M E ");
    set_header(soh++,"Riferim.@12gNumero@20gNumero@27gData@50gResiduo@102g"
                     "--------------------------------------------------------  S C A D U T O  "
                     "-------------------------------------------------------");
    set_header(soh++,"partita@12gDocum.@20gProt.@27gDocumento@38gValuta"
                     "@50gDocumento@67gNon Scaduto@86g%s@112g%s@129g%s@148g%s@167g%s@185g%s@204g%s@223g%s",
                     (const char*)s1,scaglioni[0],scaglioni[1+o],scaglioni[2+o],
                      scaglioni[3+o],scaglioni[4+o],(const char*) s2, (const char*) s3);
    set_header(soh++,(const char *)rw);
    break;
   }
   case altri:   // Piano dei conti
   {
    set_header(soh++,"@79g** SCADUTO **");
    set_header (soh++,"@73gAl %s Operazioni al %s",(const char*)limscad, (const char*)limop);
//    set_header (soh++,"@79gAl %s",(const char*)limop);
    rw.fill('-');
    set_header(soh++, (const char *) rw);                    
    set_header(soh++,"CONTO@18gD E S C R I Z I O N E");
    set_header(soh++,"Riferim.@12gNumero@20gNumero@27gData@50gResiduo@102g"
                     "--------------------------  S C A D U T O  -------------------------");
    set_header(soh++,"partita@12gDocum.@20gProt.@27gDocumento@38gValuta"
                     "@50gDocumento@67gNon Scaduto@112g%s@129g%s@148g%s@167g%s@185g%s",
                      scaglioni[0],scaglioni[5],scaglioni[6],
                      scaglioni[7],scaglioni[8]);
    set_header(soh++,(const char *)rw);
    break;
   }
   default:
    break;
  }
  set_header(soh,"");
}                          

void TStampaScaduto::set_page_clifoco(int& nriga)
{                                    
    reset_row(nriga); /**/
    set_row(nriga,"@b#t",&_cod);
    set_row(nriga/*++*/,"@18g#t@r",&_des);
}

void TStampaScaduto::set_page_part(int& nriga)
{                                 
  reset_row(nriga); /**/
  set_row(nriga,"#2t/@7s",&_anno,FLD(LF_PARTITE,PART_NUMPART));
  set_row(nriga,"@12g#t@20g#5t",&_numdoc,&_protiva);
  set_row(nriga,"@26g#t@37g#t",&_datadoc,&_codval);
  set_row(nriga,"@41g#18t",&_residuo);
  set_row(nriga,"@60g#18t",&_nonscad);
  set_row(nriga,"@79g#18t",&_buonfin);
  set_row(nriga,"@98g#18t",&_sc_1);
  set_row(nriga,"@117g#18t",&_sc_2);
  set_row(nriga,"@136g#18t",&_sc_3);
  set_row(nriga,"@155g#18t",&_sc_4);
  set_row(nriga,"@174g#18t",&_sc_5);
  set_row(nriga,"@193g#18t",&_sc_6);
  set_row(nriga,"@212g#18t",&_sc_7);
}

void TStampaScaduto::set_page(int file, int counter)
{ 
  print_header();
}

TStampaScaduto::TStampaScaduto()
{
  _rel1=_rel2=NULL;
}

int sc2300(int argc, char** argv)
{
  TStampaScaduto app;
  app.run(argc, argv, "Stampa Scaduto");    
  return 0;
}