#include <printapp.h>
#include <utility.h>
#include <tabutil.h>

#include "../cg/cgsaldac.h"
#include "../cg/cglib02.h"
#include "../sc/sc2.h"
#include "../sc/sc2201.h"    
#include "pd6292100.h"    

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

class TPRSC_recordset : public TAS400_recordset
{
public:
  TPRSC_recordset(const TString_array & colnames);
};

TPRSC_recordset::TPRSC_recordset(const TString_array & colnames) : TAS400_recordset("AS400(256,0,0)")
{
  create_field("Cliente", 0, 6, _longfld);
  create_field("RagioneSociale", -1, 50);
  create_field("Valuta", -1, 3);
	for (int i = 0; i < colnames.items(); i++)
		create_field(colnames.row(i), -1, 15, _realfld);
  create_field("Totale", -1, 15, _realfld);
  create_field("Esposto", -1, 15, _realfld);
  create_field("Saldo", -1, 15, _realfld);
  create_field("Differenza", -1, 15, _realfld);
}

///////////////////////////////////////////////////////////
// Stampa prospetto scadenze
///////////////////////////////////////////////////////////

#define NUMERO_FASCE 10
// #define LIMITI {0, 30, 60, 90, 120, 150, 180, 210, 240, 270}

enum tipo_st {clienti=0, fornitori=1};

class TLineTotal : public TObject  //Oggetto di base per i TAssoc_array dei totali
{                                     
public:  
  real _s[NUMERO_FASCE];// Scaglioni scaduto
  real _ns[NUMERO_FASCE];// Scaglioni a scadere
  real _es; // esposto
  real _sl; // saldo
  
  virtual TObject* dup() const { return new TLineTotal(*this); }
  virtual TLineTotal & copy(const TLineTotal & l);
  virtual void zero();
  TLineTotal(const TLineTotal* l) { copy(*l); }  
	TLineTotal() { zero();}
};

TLineTotal & TLineTotal::copy(const TLineTotal & l)
{
	for (int i = 0; i < NUMERO_FASCE; i++)
	{
		_s[i] = l._s[i];
		_ns[i] = l._ns[i];
	}
  _es=l._es;
  _sl=l._sl;
  return *this;
}

void TLineTotal::zero()
{
	for (int i = 0; i < NUMERO_FASCE; i++)
	{
		_s[i] = ZERO;
		_ns[i] = ZERO;
	}
  _es=ZERO;
  _sl=ZERO;
}

class TProspettoScadenze : 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;
	TTable *_val;
  tipo_st   _tipost;                                     // Tipo di stampa impostato
  bool      _end_printed,
            _start,
						_error,
            _stvaluta,
            _ordcod,                                     // VERO=ordine per codice, FALSO=ordine per ragione sociale
            _sinfasce,
            _nsinfasce;
  TString   _anno,_numdoc,_protiva,_datadoc,_codval, _codvalsel,
            _cod, _cod_pre, _des, _des_pre;
  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)
			      _sfasce,
    				_nsfasce;
	TDate			_unsdscd;
  real      _unsnc,_uns, _unsesp;                        // Unassigned per partita.
  TArray    _conti_cf,																	 // array per conti mastro
  					_t,                                          // Array per i totali
  					_ns_date,																		 // Date per non scaduto
            _s_date;                                     // Date per lo scaduto
	bool			_excel;
	TPRSC_recordset * _recset;
  
  static TString _last_game;
  static bool fil_function(const TRelation *);
	TString_array _colnames;
	int _slimiti[NUMERO_FASCE];
	int _nslimiti[NUMERO_FASCE];

public:             
	virtual const char* extra_modules() const { return "sc"; }
  virtual bool preprocess_page(int file, int counter);          
  virtual bool open_print();         
	virtual void postclose_print();
  virtual print_action postprocess_print(int file, int counter);
  virtual print_action postprocess_page(int file, int counter); 
  virtual void close_print();         
  virtual void preprocess_header() {};                          
  virtual void preprocess_footer() ;                          
  virtual bool user_create();                                   
  virtual bool user_destroy();                                  
  virtual bool set_print(int);
  virtual void set_page (int file, int counter);
  void print_totali_rows(int nriga, bool what);
  void export_totali_rows();
  void print_totali(int nriga);
  void print_header();

	int calc_last_column();
	void update_totals(bool what, real& esp, real s[NUMERO_FASCE], real ns[NUMERO_FASCE]);
  void compute_antic(TPartita& p, const TDate & datalim);
  void compute_unassigned(TPartita& p, const TDate & datalim);
  void compute_all(TPartita& p, TBill& bill);
	void print_real(TString& dest, const real& num);
	void riempi_conti_mastro(const char cf);
	void calcola_saldo();
  TProspettoScadenze();
};

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

void TProspettoScadenze::print_real(TString& dest, const real& num)
{                                   
  const bool stampa_in_valuta = _stvaluta && !_codval.blank();
  const TString& val = stampa_in_valuta ? _codval : EMPTY_STRING;
  const TCurrency cur(num, val);
  dest = cur.string(true);
  dest.right_just(10);
}

bool TProspettoScadenze::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 TProspettoScadenze::update_totals(bool what, real& esp,
                         real s[NUMERO_FASCE], real ns[NUMERO_FASCE]) 
{
  TAssoc_array& a = (TAssoc_array&) _t[what];
  TLineTotal *ll = (TLineTotal *) a.objptr(_codval);
  if (ll == NULL)               
  {
    ll = new TLineTotal;
  	a.add(_codval, ll);
  }
	for (int i = 0; i < NUMERO_FASCE; i++)
	{
	  ll->_s[i] += s[i]; 
		ll->_ns[i] += ns[i]; 
	}
  ll->_es += esp;
}                                      

void TProspettoScadenze::compute_antic(TPartita& p, const TDate & datalim)
{  
	real s[NUMERO_FASCE];
	real ns[NUMERO_FASCE];

	for (int r = p.last(); r > 0; r = p.pred(r)) // Browse all rows (partite)
  {     
    const TRiga_partite& rp = p.riga(r);
    const char * field = (_stvaluta && rp.in_valuta() ? PART_IMPORTOVAL : PART_IMPORTO);
		const TDate & d = rp.get_date(PART_DATAPAG);

		if (d > _limscad)
    {
			if (_nsinfasce)
			{
  			for (int i = _nsfasce - 1; i >= 0; i--)
				{
					const TDate & limdate = (TDate&)_ns_date[i];
					if (limdate.ok() && d > limdate)
					{
						ns[i] -= rp.get_real(field);
						break;
					}
				}
			}
			else
				ns[0] += rp.get_real(field);
    }  
    else
    {
			if (_sinfasce)
			{

				for (int i = _sfasce - 1; i >= 0; i--)
				{
					const TDate & limdate = (TDate&)_s_date[i];
					if (limdate.ok() && d <= limdate)
					{
						s[i] += rp.get_real(field);
						break;
					}
				}
			}
			else
				s[0] += rp.get_real(field);
    }
  }    
	real esposto;
  update_totals(0, esposto, s, ns); // Singolo...
  update_totals(1, esposto, s, ns); // ...Generale
}

void TProspettoScadenze::compute_unassigned(TPartita& p, const TDate & datalim)
{  
  TRecord_array& ra = p.unassigned();
  
  _uns = _unsnc = _unsesp = ZERO;
	_unsdscd = datalim;
  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);
		const TDate & datascad = sum.get_date(PART_DATAPAG);

		if ((datascad <= datalim))
		{
			_unsdscd = datascad;
			if (sum.get_int(PART_TIPOMOV) == 2) // Is it a credit note ?
				_unsnc += rec.get_real(field);
			else
				_uns += rec.get_real(field);
		}
		else
		{
			if (sum.get_int(PART_TIPOMOV) == 2) // Is it a credit note ?
				_unsesp -= rec.get_real(field);
			else
				_unsesp += rec.get_real(field);
		}

  }    
}

void TProspettoScadenze::compute_all(TPartita& p, TBill& bill)
{ 
  real residuo;
	real s[NUMERO_FASCE];
	real ns[NUMERO_FASCE];
	real res_pagati;
	real esposto;

  compute_unassigned(p, _limbf);
	esposto = _unsesp;
  for (int r = p.last(); r > 0; r = p.pred(r)) // Browse all rows (partite)
  {
    const TRiga_partite& rp = p.riga(r);
    // se la data di registrazione della partita ' > di _limop (data lim operazione)
    // non deve scorrere le scadenze
    const 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)
    {  
      const TRiga_scadenze& rs = rp.rata(n);
      const 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(ssez,rs.get_real(sfield));					// Importo in scadenza...
      TImporto pag(rs.importo_pagato_al(_stvaluta, _limop));     // Quanto e' stato pagato per questa scadenza?
      TImporto bf;
      TImporto work_imp;
			
			// 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
      
      int pp;
      for (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);
        const tipo_movimento tipomov  = (tipo_movimento) sum.get_int(PART_TIPOMOV);

        if (tipomov != tm_insoluto && 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 == tm_nota_credito)
        {
          work_imp = TImporto(sez,pg.get_real(field));
          scd += work_imp;
          pag -= work_imp;
        }
        if ((tipomov == tm_pagamento || tipomov == tm_pagamento_insoluto) && _tipost == clienti)
        {
          TDate data_pag(sum.get_date(PART_DATAPAG));
          const int tipo_pag = sum.get_int(PART_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));
          }
        }
      }          
      
			const char scd_sez = (_tipost == fornitori ? 'A' : 'D');  
			const char pag_sez = (_tipost == fornitori ? 'D' : 'A');  

			scd.normalize(scd_sez);
			
			real rscd = scd.valore();
			
			pag -= bf;
      pag.normalize(pag_sez);
			
			real rpag = pag.valore();

      real res = rscd - rpag; // Scadenze - pagati = scaduto per questo gruppo di rate

      if (_uns > ZERO)  // 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
        res -= gap;
        _uns -= gap; // aggiorna la cache..
      }
      if (_unsnc > ZERO) // Rettifica le scadenze con le N.C non assegnate.
      {
        real gap = (_unsnc > rscd ? rscd : _unsnc);
        rscd -= gap;
        res -= gap;
        _unsnc -= gap;
      }
      if (rscd == ZERO) // Se le scadenze sono a zero, vuol dire che sono state stornate
        res = ZERO;  // da qualche nota di credito o non assegnato  percio' non si ha residuo

			if (d > _limscad)
      {
				if (_nsinfasce)
				{
    			for (int i = _nsfasce - 1; i >= 0; i--)
					{
						const TDate & limdate = (TDate&)_ns_date[i];
						if (limdate.ok() && d > limdate)
						{
							ns[i] += res;
							break;
						}
					}
				}
				else
					ns[0] += res;
      }  
      else
      {
				if (_sinfasce)
				{

					for (int i = _sfasce - 1; i >= 0; i--)
					{
						const TDate & limdate = (TDate&)_s_date[i];
						if (limdate.ok() && d <= limdate)
						{
							s[i] += res;
							break;
						}
					}
				}
				else
					s[0] += res;
      }
      residuo += res;
      bf.normalize(pag_sez);
			esposto += bf.valore();
    } 
  }

  // Aggiorna i totali... 
  update_totals(0, esposto, s, ns); // Singolo...
  update_totals(1, esposto, s, ns); // ...Generale
}

void TProspettoScadenze::calcola_saldo()
{   
  TAssoc_array& a = (TAssoc_array&) _t[0];
  TLineTotal *ll = (TLineTotal *) a.objptr(_codval);
	TEsercizi_contabili e;
	TSaldo saldo;
	int g,c;
	const long s = atol(_cod_pre);
	
	for (int i = 0; i < _conti_cf.items(); i++)
	{                             
		TToken_string& cf = (TToken_string&)_conti_cf[i];
	  g = cf.get_int(0);
  	c = cf.get_int(1);
    TToken_string key; 
    key.add(g); key.add(c); key.add("");
    const TRectype& pc = cache().get(LF_PCON, key);
    int indbil_conto = pc.get_int (PCN_INDBIL);
		const int codes = e.date2esc(_limop);
		saldo.set_annoes(codes);
  	TDate dataini(e.esercizio(codes).inizio());
    saldo.data_limite_bilancio( 1, g, c, s, dataini, _limop, indbil_conto, false); 
		if (_tipost == fornitori)
	  	ll->_sl -= saldo.saldo(); 
		else
			ll->_sl += saldo.saldo(); 
	}
	// aggiorno il totale generale
	TAssoc_array& at = (TAssoc_array&) _t[1];
  TLineTotal *lt = (TLineTotal *) at.objptr(_codval);
	if (lt == NULL)               
	{
		lt = new TLineTotal;
  	at.add(_codval, lt);
	}
  lt->_sl += ll->_sl;
}

bool TProspettoScadenze::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 (((TAssoc_array&) _t[0]).items() > 0)
        print_totali(1); 
      _des.trim();
      _cod_pre = _cod;
      _des_pre = _des;
    }

    if (!curr.empty())
		{
			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)  //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);
			}
			else
			{
				compute_unassigned(p, _limbf);

				real residuo;
				real s[NUMERO_FASCE];
				real ns[NUMERO_FASCE];
				real esposto;
				const TDate d(_unsdscd);
				real res = - _uns - _unsnc;

      
				if (d > _limscad)
				{
					if (_nsinfasce)
					{
    				for (int i = _nsfasce - 1; i >= 0; i--)
						{
							const TDate & limdate = (TDate&)_ns_date[i];
							if (limdate.ok() && d > limdate)
							{
								ns[i] += res;
								break;
							}
						}
					}
					else
						ns[0] += res;
				}  
				else
				{
					if (_sinfasce)
					{

						for (int i = _sfasce - 1; i >= 0; i--)
						{
							const TDate & limdate = (TDate&)_s_date[i];
							if (limdate.ok() && d <= limdate)
							{
								s[i] += res;
								break;
							}
						}
					}
					else
						s[0] += res;
				}
				residuo += res;
				esposto = _unsesp;
			  update_totals(0, esposto, s, ns); // Singolo...
				update_totals(1, esposto, s, ns); // ...Generale
			}
			current_cursor()->repos(); // Very, very necessary...
		}
  }
  return true;
}

bool TProspettoScadenze::open_print()
{
	if (_error)
		return false;
	if (_stvaluta)
	{
		const int err = _start ? _val->first() : _val->next();
		if (err != NOERR)
			return false;
	}
	_codvalsel = _val->get("CODTAB");
	reset_files();
	reset_print();
	printer().footerlen(5);
	if (_m->get_who() == 'C') 
		_tipost = clienti;
	else 
		_tipost = fornitori;
	riempi_conti_mastro(_m->get_who());
	if (_m->get_key() == 1) 
		_ordcod = true;
	else 
		_ordcod = false;
	_end_printed = false;
	_gcr      = _m->get_int(F_GIORNI);
	_datas    = _m->get_date(F_DATASTAMPA);
	_limop    = _m->get_date(F_DATAOPERAZIONE);
	_limscad  = _m->get_date(F_DATASCADUTO);
	_limbf = _limscad - (long)_gcr; // Limite inferiore per le scadenze a Buon Fine.
	_sinfasce = _m->get_bool(F_SCADINFASCE);
	_nsinfasce = _m->get_bool(F_ASCADINFASCE);
	_s_date.destroy();
	_ns_date.destroy();
	for (int i = 0; i <= NUMERO_FASCE; i++)
	{
		_s_date.add(new TDate);
		_ns_date.add(new TDate);
	}  
	for (int j = 0; j < _sfasce; j++)
	{
		TDate & d =	(TDate &)_s_date[j];
		d = _limscad;
 		d.addmonth(-_slimiti[j]);
	}
	for (int k = 0; k < _nsfasce; k++)
	{
 		TDate & d = (TDate &)_ns_date[k];
 		d = _limscad;
 		d.addmonth(_nslimiti[k]);
	}
	_anno.cut(0);_numdoc.cut(0);_protiva.cut(0);_datadoc.cut(0);
	_codval.cut(0);_cod.cut(0); _des.cut(0); _cod_pre.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:
		 {
			 TString filter;

			 filter_from.put("TIPOC", _tipost == clienti ? "C" : "F");
			 filter_to = filter_from;
			 if (_stvaluta)
			 {
				 if (is_firm_value(_codvalsel))
					 filter << "(CODVAL==\"\")||";
				 filter << "(CODVAL==\"" << _codvalsel << "\")";
			 }
			 if (_ordcod) // Per codice...
			 {
				 select_cursor(_cur1);
				 get_cursor(_cur1)->setregion(filter_from, filter_to);
				 get_cursor(_cur1)->setfilter(filter);
			 }
			 else     // ... e ragione sociale
			 {
				 select_cursor(_cur2);
				 get_cursor(_cur2)->setregion(filter_from, filter_to);
				 get_cursor(_cur2)->setfilter(filter);
			 }
			 add_file(LF_PARTITE);
			 add_file(LF_CLIFO,LF_PARTITE);
		 }
		 break;
	 default: break;
	} // End of inner switch
	if (_excel)
	{	
		_colnames.destroy();
		if (_sinfasce)
		{
			_colnames.add(format("Scaduto > %3d gg", _slimiti[_sfasce - 1] * 30));
			for (int i = _sfasce - 1; i > 0; i--)
 				_colnames.add(format("Scaduto <= %3d gg", _slimiti[i] * 30));
		}
		else
 				_colnames.add("Scaduto");
		if (_nsinfasce)	
		{
			for (int i = 0; i < _nsfasce; i++)
				_colnames.add(format("A Scadere <= %3d gg", _nslimiti[i] * 30));
			_colnames.add(format("A Scadere > %3d gg", _nslimiti[_nsfasce - 1] * 30));
		}
		else
 				_colnames.add("A Scadere");
		_recset = new TPRSC_recordset(_colnames);
	}
	_start = false ;
	return true;
}

print_action TProspettoScadenze::postprocess_print(int file, int counter)
{  
  print_action rt = NEXT_PAGE;            
  if (!_end_printed)
	{
    if ((file == LF_PARTITE))
    {             
      rt = REPEAT_PAGE;
      _end_printed = true;
    }
	}
	else
  {
    if (((TAssoc_array&) _t[0]).items() > 0)
		{
      print_totali(1);
			print_one(0);
    }
    if (((TAssoc_array&) _t[1]).items() > 0)
		{
      print_totali_rows(1,1);
			print_one(0);
    }
  }
  return rt;
}

void TProspettoScadenze::postclose_print() 
{  
	if (_excel)
	{
    TFilename slk; slk.tempdir(); slk.add("prosscad.xls");
    _recset->save_as(slk, fmt_html);
    xvt_sys_goto_url(slk, "open");
		delete _recset;
		_recset = NULL;
	}
}

void TProspettoScadenze::close_print()
{
	if (_stvaluta)
		repeat_print();
}

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

bool TProspettoScadenze::user_create()
{                                                
  _rel1 = new TRelation(LF_PARTITE);
  _rel1->add(LF_CLIFO,"TIPOCF=TIPOC|CODCF=SOTTOCONTO",1);
  _cur1 = add_cursor(new TCursor(_rel1)); 
  _cur2 = add_cursor(new TSorted_cursor(_rel1,"UPPER(20->RAGSOC)||NUMPART","",1));

  _rel2 = new TRelation(LF_PARTITE);           
  _rel2->add(LF_PCON,"GRUPPO=GRUPPO|CONTO=CONTO|SOTTOCONTO=SOTTOCONTO",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);
	_val = new TTable("%VAL");
  _t.add(new TAssoc_array);_t.add(new TAssoc_array);

  TConfig conf (CONFIG_DITTA,"cg");
  _m = new TSelection_ext_mask("pd6292100a");
  _m->enable(F_VALUTA,conf.get_bool("GesVal")); 
	_stvaluta = false; 
	_start = true;

  enable_print_menu();               
  return true;
}

bool TProspettoScadenze::user_destroy()
{
  if (_rel1)  delete _rel1;
  if (_rel2)  delete _rel2;
  if (_scad)     delete _scad;
  if (_pagsca)   delete _pagsca;
  if (_val)  delete _val;
  if (_m) delete _m;
  _t.destroy();
  return true;
}

void TProspettoScadenze::riempi_conti_mastro(const char cf)
{                          
	_conti_cf.destroy();
	TRelation rel = TRelation(LF_PCON);
	TString80 filtro;
	filtro.format("TMCF==\'%c\'", cf);
	TCursor cur(&rel, filtro);
  TToken_string gc(10);
	for (cur=0; cur.pos() < cur.items(); ++cur)
	{   
		const int g = cur.curr().get_int(PCN_GRUPPO);
		const int c = cur.curr().get_int(PCN_CONTO);
		gc.add(g,0);
		gc.add(c,1);
	  _conti_cf.add(gc);
	}
}

bool TProspettoScadenze::set_print(int)
{ 
	const bool repeat = _stvaluta && need_to_repeat_print();
	bool print = repeat;

	if (!repeat)
	{
		KEY k  = _m->run();
		_excel = k != K_ENTER;
		_sfasce = 0;
		_slimiti[_sfasce++] = 0;
		for (short id = F_SCADFASCE1; id <= F_SCADFASCE9; id++)
		{
			int nmesi = _m->get_int(id);

			if (nmesi == 0)
				break;
			nmesi += _slimiti[_sfasce - 1];
			_slimiti[_sfasce++] = nmesi;
		}
		_nsfasce = 0;
		_nslimiti[_nsfasce++] = 0;
		for (short id = F_ASCADFASCE1; id <= F_ASCADFASCE9; id++)
		{
			int nmesi = _m->get_int(id);

			if (nmesi == 0)
				break;
			nmesi += _nslimiti[_nsfasce - 1];
			_nslimiti[_nsfasce++] = nmesi;
		}
		print = k != K_QUIT;
		_error = false;
		if (print && (_sfasce + _nsfasce) > 9)
			_error = !error_box("Il numero di totale fasce non puo' superare 9");
		_start = true;
	}
  _stvaluta = _m->get_bool(F_VALUTA);
  return print;
}

void TProspettoScadenze::print_totali_rows(int nriga, bool what)
// If what is 0 prints single total... else prints also general total
{
	reset_print();
  TAssoc_array& xassoc = (TAssoc_array&) _t[what];
	if (_cod_pre.blank())
	{
	  xassoc.destroy();
		return;
	}
  TString_array as;
  const int items = xassoc.items();

  xassoc.get_keys(as);
  as.sort();
  for (int i=0; i < items; i++)
  {
    if (!what && !_excel)
    	calcola_saldo();

    TString k(as.row(i)); // Chiave di ordinamento(valuta)
    TString value;
    TLineTotal& v = (TLineTotal&)xassoc[k];
		real tot = ZERO;
   	int pos = 40;
   	TString rw(255);
   	
		rw = "";
		if (_sinfasce)
		{        
			for (int i = _sfasce - 1; i >= 0; i--)
			{
				if (v._s[i] != ZERO)              
				{
			    print_real(value, v._s[i]);
		      rw << format("@%dg%13s", pos, (const char*) value);
					tot += v._s[i];
			  }  
	    	pos += 13;
			}
		}
		else
		{
			if (v._s[0] != ZERO)              
			{
			  print_real(value, v._s[0]);
		    rw << format("@%dg%13s", pos, (const char*) value);
				tot += v._s[0];
			}  
	    pos += 13;
		}
	
   	if (_nsinfasce)
   	{
			for (int i = 0; i < _nsfasce; i++)
			{
				if (v._ns[i] != ZERO)
				{
					print_real(value, v._ns[i]);
					rw << format("@%dg%13s", pos, (const char*) value);
					tot += v._ns[i];
				}  
		    pos += 13;
			}
		}
		else
		{
			if (v._ns[0] != ZERO)
			{
				print_real(value, v._ns[0]);
				rw << format("@%dg%13s", pos, (const char*) value);
				tot += v._ns[0];
			}  
		  pos += 13;
		}
	
    if (tot != ZERO)
    {
	   	print_real(value, tot);
      rw << format("@%dg%13s", pos, (const char*) value);
    }  
		pos += 13;
    if (v._es != ZERO)
    {
			print_real(value, v._es);
			rw << format("@%dg%13s", pos, (const char*) value);
    }  
		pos += 13;
    if (v._sl != ZERO)
    {
	    print_real(value, v._sl);
      rw << format("@%dg%13s", pos, (const char*) value);
    }  
		pos += 13;
    
		const real diff = v._sl - (tot - v._es);
	  if (diff != ZERO)
	  {                        
	    print_real(value, diff);
	    rw << format("@%dg%13s", pos, (const char*) value);
		}
    
    if (rw.not_empty())
    {
    	if (!what)
			{
				TString s = _des_pre.left(25);
   			rw.insert(format("%6s@8g%-25s", (const char*) _cod_pre, (const char*) s));
			}
   		else
			{
				TString meno;
				const int last_column = calc_last_column();

				meno.fill('-', last_column);
				set_row(nriga++, meno);
				rw.insert("@8gTOTALE GENERALE");   			
			}
    	set_row(nriga, rw);                           
    }	
  } 
  xassoc.destroy(); // Distrugge il totale appena stampato 
}
                    

void TProspettoScadenze::export_totali_rows()
// If what is 0 prints single total... else prints also general total
{
	if (_cod_pre.blank())
		return;
  TAssoc_array& xassoc = (TAssoc_array&) _t[0];
  TString_array as;
  const int items = xassoc.items();

  xassoc.get_keys(as);
  as.sort();
  for (int i=0; i < items; i++)
  {
		TVariant var(_cod_pre);
    TString k(as.row(i)); // Chiave di ordinamento(valuta)
    TLineTotal& v = (TLineTotal&)xassoc[k];
		real t1;
		real t2;

		calcola_saldo();
		for (int j = NUMERO_FASCE; j >= 0; j--)
			t1 += v._s[j];
		for (int jj = 0; jj <= NUMERO_FASCE; jj++)
			t2 += v._ns[jj];
		if (t1 == ZERO && t2 == ZERO && v._es == ZERO && v._sl == ZERO)
			continue;
		_recset->new_rec();
		_recset->set("Cliente", var);
		var = _des_pre;
		_recset->set("RagioneSociale", var);
		var = k;
		_recset->set("Valuta", var);
		int col = 0;
		real tot = ZERO;

		if (_sinfasce)
		{        
			for (int i = _sfasce - 1; i >= 0; i--)
			{
			  _recset->set(_colnames.row(col++), v._s[i]);
				tot += v._s[i];
			}
		}
		else
		{
			_recset->set(_colnames.row(col++), v._s[0]);
			tot += v._s[0];
		}
	
   	if (_nsinfasce)
   	{
			for (int i = 0; i < _nsfasce; i++)
			{
			  _recset->set(_colnames.row(col++), v._ns[i]);
				tot += v._ns[i];
			}
		}
		else
		{
		  _recset->set(_colnames.row(col), v._ns[0]);
			tot += v._ns[0];
		  col++;
		}
	
		const real diff = v._sl - (tot - v._es);

		_recset->set("Totale", tot);
		_recset->set("Esposto", v._es);
		_recset->set("Saldo", v._sl);
		_recset->set("Differenza", diff);
  } 
}
                    
void TProspettoScadenze::print_totali(int nriga)
{ 
  reset_row(nriga);
	if (_excel)
	  export_totali_rows();
	print_totali_rows(nriga,0);
}

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

  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();
	TString s1;

	if (_stvaluta)
		s1 << "Valuta : " << _codvalsel << " " << _val->get("S0");

  set_header (soh++, "Ditta : %ld %s@%ldg%s@%ldgData %s @%ldgPag. @#",
             firm, (const char *)s, (last_column - s1.len()) / 2, (const char *)s1,last_column - 30, (const char *)datas, last_column - 10);
             
  switch (_tipost)
  {
   case fornitori:
   case clienti:    
   {                           
    TString s1,s2, s3, lim;
    int o = 0; // Offset per scaglioni.


    if (_tipost==fornitori)   
     set_header(soh++,"@%ldg** PREVISIONE PAGAMENTI FORNITORI **", (last_column - 37) / 2);
    else                   
     set_header(soh++,"@%ldg** PREVISIONE INCASSI CLIENTI **", (last_column - 34) / 2);
    set_header (soh++,"@%ldgAl %s - Operazioni al %s", (last_column - 40) / 2, (const char*)limscad, (const char*)limop);
	  meno.fill('-', last_column);
    set_header(soh++,(const char *)meno);
    set_header(soh,"CODICE@8gR A G I O N E    S O C I A L E ");
   	int pos = 40;
		
		rw.cut(0);
    if (_sinfasce)
    {
    	rw << format("@%dg   >%3d gg", pos, _slimiti[_sfasce - 1] * 30);
    	pos += 13;
			for (int i = _sfasce -1 ; i > 0; i--)
			{
    		rw << format("@%dg <= %3d gg", pos, _slimiti[i] * 30);
    		pos += 13;
    	}                
    	set_header(soh, format("@%dg%s",40+((pos-40)/2), "SCADUTO"));
    }
    else
		{
    	set_header(soh, format("@%dg%13s", pos, "SCADUTO"));
   		pos += 13;
		}

    const int pos_ascad = pos;
    if (_nsinfasce)	
    {
    	for (int i = 0; i < _nsfasce; i++)
    	{
    		rw << format("@%dg <= %3d gg", pos, _nslimiti[i] * 30);
    		pos = pos + 13;
    	}
    	rw << format("@%dg   >%3d gg", pos, _nslimiti[_nsfasce - 1] * 30);
    	pos = pos + 13;
    	set_header(soh, format("@%dg%s", pos_ascad+((pos-pos_ascad)/2)-5, "A SCADERE"));
    }
    else
		{
    	set_header(soh, format("@%dg%13s", pos, "A SCADERE"));
			pos += 13;
		}
   	set_header(soh, format("@%dg%13s", pos, "TOTALE"));
		pos += 13;
   	set_header(soh, format("@%dg%13s", pos, "ESPOSTO"));
		pos += 13;
   	set_header(soh, format("@%dg%13s", pos, "SALDO"));
		pos += 13;
   	set_header(soh, format("@%dg%13s", pos, " DIFFERENZA"));
    set_header(++soh,(const char *)rw);
    break;
   }
   default:
    break;
  }
  set_header(++soh, (const char *) meno);                          
}                          

void TProspettoScadenze::preprocess_footer()
{ 
}
              
int TProspettoScadenze::calc_last_column()
// Setta le righe dell'intestazione
{
 	int pos = 112;
		
    if (_sinfasce)
  		pos += _sfasce * 13;
		else
			pos += 13;
    if (_nsinfasce)	
   		pos = pos + _nsfasce * 13;
		else
			pos += 13;
	return pos;
}                          

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

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

int pd6292100(int argc, char** argv)
{
  TProspettoScadenze app;
  app.run(argc, argv, TR("Stampa Previsione Incassi/Pagamenti"));    
  return 0;
}