#include <diction.h>
#include <lffiles.h>
#include <prefix.h>

#include <causali.h>
#include <clifo.h>
#include <mask.h>
#include <mov.h>
#include <pconti.h>
#include <rmov.h>
#include <riclpdc.h>
#include <saldi.h>
#include <tabutil.h>

#include "../cg/cglib02.h"

#include "rilib01.h"

class TSaldo_ricl : public TSaldo
{
	TArray _progdare;
	TArray _progavere;

public:
  const real& saldo_periodo(int g, int c, long s, const TArray & dal, const TArray& al, bool provv);
  const real& progdare(int p) const { return (real&) _progdare[p];}
  const real& progavere(int p) const { return (real&) _progavere[p];}
	TSaldo_ricl() { }
  virtual ~TSaldo_ricl() {}
};

const real& TSaldo_ricl::saldo_periodo(int g, int c, long s, const TArray & dal, const TArray & al, bool provv)
{
	saldoini_ref() = ZERO;
  saldo_ref() = ZERO;
  prgdare_ref() = ZERO;
  prgavere_ref() = ZERO;
  set_movimentato(false);

	_progdare.destroy();
	_progavere.destroy();

	const int nper = al.items();
  if (nper <= 0)
    return ZERO;

  for (int p = 0; p < nper; p++)
	{
		_progdare.add(new real);
		_progavere.add(new real);
	}

	const TDate & da = (const TDate &) dal[0];
	const TDate & a = (const TDate &) al[nper - 1];

  TEsercizi_contabili es;
  const int codes = es.date2esc(da);
	const TDate inizio = es.esercizio(codes).inizio();

  TString80 key; key.format("%04d| |%d|%d|%ld", codes, g, c, s);
	const TRectype& saldo = cache().get(LF_SALDI, key);

	key.format("%d|%d", g, c);
  const int indbil = atoi(cache().get(LF_PCON, key, PCN_INDBIL));

	if ((indbil <= 2 || indbil == 5) && saldo.get_real(SLD_SALDO).is_zero())  
		saldoini_ref() = saldofin_esprec(codes,g,c,s);
	else
  {
		if (saldo.get_char(SLD_FLAGSALINI) == 'A')
			saldoini_ref() = -saldo.get_real(SLD_SALDO);
		else
			saldoini_ref() = saldo.get_real(SLD_SALDO);
  }
  
  TRelation relrmov(LF_RMOV);
	TRectype& rmov = relrmov.curr();
  rmov.put(RMV_GRUPPO,g);
  rmov.put(RMV_CONTO,c);
  rmov.put(RMV_SOTTOCONTO,s);

  TCursor cur(&relrmov, "", 2, &rmov,  &rmov);
	const TRecnotype items = cur.items();

  if (items > 0)
  {
	  cur.freeze();      

    TProgind* p = NULL;
    if (items > 100)  // E' proprio utile la progind?
    {
	    TString80 prompt;
	    prompt.format(FR("Calcolo saldo del conto %d.%d.%ld"), g, c, s);
	    p = new TProgind(items, prompt, false);
    }

    for (cur = 0L; cur.pos() < items; ++cur)
    { 
      if (p != NULL)
        p->addstatus(1L);
		  
		  const long num_reg  = rmov.get_long(RMV_NUMREG);
		  const real importo  = rmov.get_real(RMV_IMPORTO);

		  if (!importo.is_zero())
		  {
			  const char sezione  = rmov.get_char(RMV_SEZIONE);
			  // "Se la causale del movimento e' di chiusura, 
			  //  o di apertura il movimento non va considerato"
				const TRectype& mov = cache().get(LF_MOV, num_reg);  
				const TDate & datacomp = mov.get_date(MOV_DATACOMP);
				const TRectype& cau = cache().get(LF_CAUSALI, mov.get(MOV_CODCAUS));  

			  if ((provv || !mov.get_bool(MOV_PROVVIS)) && cau.get(CAU_MOVAP).blank())
			  {
				  if (datacomp >= da && datacomp <= a)
				  {
						int per = 0;

						set_movimentato();
						for (per = 0; per < nper; per++)
							if (datacomp <= (const TDate &) al[per])
								break;
					  if (sezione == 'D') 
						{
						  prgdare_ref() += importo;
							if (per < nper)
								((real&)_progdare[per]) += importo;
						}
					  else 
						{
					    prgavere_ref() += importo;
							if (per < nper)
								((real&)_progavere[per]) += importo;
						}
				  }
				  else
					  if (datacomp >= inizio && datacomp < da)
					  {   
						  if (sezione == 'D')  
							  saldoini_ref() += importo;
						  else 
							  saldoini_ref() -= importo;
					  }    
			  }
		  }
    }
    if (p != NULL)
      delete p;
  }
  saldo_ref() = saldoini_ref() + prgdare_ref() - prgavere_ref();
  return saldo_ref();
}

class TSaldo_periodo : public TObject
{
	TArray _saldo_iniziale;
	TArray _prog_dare;
	TArray _prog_avere;
	TArray _saldo;
	bool _movimentato;

public:
	TVariant & saldoini(int nper) { return (TVariant &) _saldo_iniziale[nper]; }
	TVariant & pavere(int nper) { return (TVariant &) _prog_avere[nper]; }
	TVariant & pdare(int nper) { return (TVariant &) _prog_dare[nper]; }
	TVariant & saldo(int nper) { return (TVariant &) _saldo[nper]; }
	const TVariant & saldoini(int nper) const { return (TVariant &) _saldo_iniziale[nper]; }
	const TVariant & pavere(int nper) const { return (TVariant &) _prog_avere[nper]; }
	const TVariant & pdare(int nper) const { return (TVariant &) _prog_dare[nper]; }
	const TVariant & saldo(int nper) const { return (TVariant &) _saldo[nper]; }
	const int nper() const { return _saldo.items(); }
	void update(char tcf, int gruppo, int conto, long sottoconto, bool provv, const TArray & from, const TArray & to, bool prog);

	bool is_zero() const;
	bool movimentato() const { return _movimentato;}
	const TSaldo_periodo & operator +=(const TSaldo_periodo & sp);
	const TSaldo_periodo & operator -=(const TSaldo_periodo & sp);

	TSaldo_periodo(int items);
	TSaldo_periodo(char tcf, int gruppo, int conto, long sottoconto, bool provv, const TArray & from, const TArray & to, bool prog);
	virtual ~TSaldo_periodo() {}
};

void TSaldo_periodo::update(char tcf, int gruppo, int conto, long sottoconto, bool provv, const TArray & from, const TArray & to, bool prog)
{
	TSaldo_ricl sal;
	const int nper = from.items();

	_saldo_iniziale.destroy();
	_prog_avere.destroy();
	_prog_dare.destroy();
	_saldo.destroy();
	_movimentato = false;
	for (int i = 0; i < nper; i++)
	{
		_saldo_iniziale.add(new TVariant(ZERO));
		_prog_avere.add(new TVariant(ZERO));
		_prog_dare.add(new TVariant(ZERO));
		_saldo.add(new TVariant(ZERO));
	}

	if (sottoconto == 0L) // E' un conto
	{ 
		if (tcf > ' ')
		{
			TRelation relcf(LF_CLIFO);
			TRectype & clifo = relcf.curr();
			clifo.put(CLI_TIPOCF, tcf);
			TCursor cur(&relcf, "", 1, &clifo, &clifo);
			const TRecnotype items = cur.items();
		  
			cur.freeze();

			TString prompt = tcf == 'C' ? TR("Ricalcolo saldi Clienti") : TR("Ricalcolo saldi Fornitori");
			prompt << ' ' << gruppo << ' ' << conto;

			TProgind p(items, prompt, FALSE);
			for (cur = 0L; !p.iscancelled() &&  cur.pos() < items; ++cur)
			{ 
				const long sottocontocli = clifo.get_long(CLI_CODCF);
				real si[255], pa[255], pd[255], sf[255];

				sal.saldo_periodo(gruppo, conto, sottocontocli, from, to, provv);
				real sld = sal.saldoini();

				_movimentato |= sal.movimentato();
				for (int i = 0; i < nper; i++)
				{
					if (prog)
					{
						si[i] = sal.saldoini();
						pa[i] += sal.progavere(i);
						pd[i] += sal.progdare(i);
					}
					else
					{
						si[i] = sld;
						pa[i] = sal.progavere(i);
						pd[i] = sal.progdare(i);
					}
					sld += pd[i] - pa[i];
					sf[i] = sld;
				}
				for (int i = 0; i < nper; i++)
				{
					saldoini(i) += si[i];
					pavere(i) += pa[i];
					pdare(i) += pd[i];
					saldo(i) += sf[i];
				}
				p.addstatus(1L);
			}
		}
	}
  else
  {         
		sal.saldo_periodo(gruppo, conto, sottoconto, from, to, provv);

		real sld = sal.saldoini();

		_movimentato = sal.movimentato();
		for (int i = 0; i < nper; i++)
		{
			if (prog)
			{
				saldoini(i) = sal.saldoini();
				pavere(i) += sal.progavere(i);
				pdare(i) += sal.progdare(i);
			}
			else
			{
				saldoini(i) = sld;
				pavere(i) = sal.progavere(i);
				pdare(i) = sal.progdare(i);
			}
			sld += pdare(i).as_real() - pavere(i).as_real();
			saldo(i) = sld;
		}
	}
}

bool TSaldo_periodo::is_zero() const
{
	const int items = nper();
	for (int i = 0; i < items; i++)
	{
		if (!saldoini(i).as_real().is_zero())
			return false;
		if (!pavere(i).as_real().is_zero())
			return false;
		if (!pdare(i).as_real().is_zero())
			return false;
		if (!saldo(i).as_real().is_zero())
			return false;
	}
	return true;
}

const TSaldo_periodo & TSaldo_periodo::operator +=(const TSaldo_periodo & sp)
{
	const int items_to_add = min(nper(), sp.nper());
	for (int i = 0; i < items_to_add; i++)
	{
		saldoini(i) += sp.saldoini(i);
		pavere(i) += sp.pavere(i);
		pdare(i) += sp.pdare(i);
		saldo(i) += sp.saldo(i);
	}
	_movimentato |= sp.movimentato();
	return *this;
}

const TSaldo_periodo & TSaldo_periodo::operator -=(const TSaldo_periodo & sp)
{
	const int items_to_sub = min(nper(), sp.nper());
	for (int i = 0; i < items_to_sub; i++)
	{
		saldoini(i) += sp.saldoini(i);
		pavere(i) += sp.pavere(i);
		pdare(i) += sp.pdare(i);
		saldo(i) += sp.saldo(i);
	}
	_movimentato |= sp.movimentato();
	return *this;
}

TSaldo_periodo::TSaldo_periodo(int items)
{
	_saldo_iniziale.destroy();
	_prog_avere.destroy();
	_prog_dare.destroy();
	_saldo.destroy();
	for (int i = 0; i < items; i++)
	{
		_saldo_iniziale.add(new TVariant(ZERO));
		_prog_avere.add(new TVariant(ZERO));
		_prog_dare.add(new TVariant(ZERO));
		_saldo.add(new TVariant(ZERO));
	}
	_movimentato = false;
}

TSaldo_periodo::TSaldo_periodo(char tcf, int gruppo, int conto, long sottoconto, bool provv, const TArray & from, const TArray & to, bool prog)
{
	update(tcf, gruppo, conto, sottoconto, provv, from, to, prog);
	_movimentato = false;
}

class TSaldi_recordset_data :public TObject
{
	TAssoc_array _saldi;
	int _nper;
	TArray _from;
	TArray _to;
	bool _provv;
	bool _prog;
	TString16 _codricl;
	TString8 _table;

public:
	TAssoc_array & saldi() { return _saldi; }
	int & nper() { return _nper; }
	TArray & from() { return _from; }
	TArray & to() { return _to; }
	bool & provv() { return	_provv; }
	bool & prog() { return	_prog; }
	TString & codricl() { return _codricl; }
	TString & table() { return _table; }
	TSaldi_recordset_data() : _nper(0), _provv(0) {	}
	virtual ~TSaldi_recordset_data() { }
};

HIDDEN TArray __shuttle;
HIDDEN int __curr_id = -1;

HIDDEN TSaldi_recordset_data & saldi_data() { return *(TSaldi_recordset_data *) __shuttle.objptr(__curr_id); }
HIDDEN TSaldi_recordset_data & saldi_data(int id) { __curr_id = id; return *(TSaldi_recordset_data *) __shuttle.objptr(id); }

const TSaldo_periodo & saldo_periodo_conto(char tcf, int gruppo, int conto, long sottoconto) 
{
	TSaldi_recordset_data & data = saldi_data();
	TToken_string key;
	key.add(gruppo);
	key.add(conto);
	key.add(sottoconto);
	TSaldo_periodo * values = (TSaldo_periodo *) data.saldi().objptr(key);

	if (values == NULL)
	{
		if (sottoconto > 0L || tcf > ' ')
			values = new TSaldo_periodo(tcf, gruppo, conto, sottoconto, data.provv(), data.from(), data.to(), data.prog());
		else
			values = new TSaldo_periodo(data.from().items());
		data.saldi().add(key, values);
	}
	return * values;
}
const TSaldo_periodo & saldo_periodo_conto(int id, char tcf, int gruppo, int conto, long sottoconto) 
{
	__curr_id = id;

	return saldo_periodo_conto(tcf, gruppo, conto, sottoconto);
}

const TSaldo_periodo & saldo_periodo_ricl(const char * codricl, const char *cod) 
{
	TSaldi_recordset_data & data = saldi_data();
	TSaldo_periodo * values = (TSaldo_periodo *) data.saldi().objptr(cod);

	if (values == NULL)
	{
		values = new TSaldo_periodo(data.nper());

		TString query ;
		TString fromto;

		query  <<"USE " << LF_RICLPDC << " KEY 3\n";
		fromto << RICLPDC_TIPORIC << "=" << codricl << " " << RICLPDC_CODICE << "=" << cod;
		query << "FROM " << fromto << "\nTO " << fromto << "\n";

		TISAM_recordset ricl(query);

		for (bool ok = ricl.move_first(); ok ; ok = ricl.move_next())
		{
			const int gruppo = ricl.get(PCN_GRUPPO).as_int();
			const int conto = ricl.get(PCN_CONTO).as_int();
			const long sottoconto = ricl.get(PCN_SOTTOCONTO).as_int();

			query = "USE "; query << LF_PCON << "\n";
			fromto = PCN_GRUPPO; fromto << "=" << gruppo;
			if (conto > 0)
				fromto << " " << PCN_CONTO << "=" << conto;
			if (sottoconto > 0)
				fromto << " " << PCN_SOTTOCONTO << "=" << sottoconto;
			query << "FROM " << fromto << "\nTO " << fromto << "\n";
			TISAM_recordset conti(query);

			for (bool ok = conti.move_first(); ok ; ok = conti.move_next())
			{
				const int gruppoc = conti.get(PCN_GRUPPO).as_int();
				const int contoc = conti.get(PCN_CONTO).as_int();
				const long sottocontoc = conti.get(PCN_SOTTOCONTO).as_int();
				const char tcf = conti.get(PCN_TMCF).as_string()[0];

				TSaldo_periodo s(tcf, gruppoc, contoc, sottocontoc, data.provv(), data.from(), data.to(), data.prog());
				*values += s;
			}
		}
		data.saldi().add(cod, values);
	}
	return * values;
}

const TSaldo_periodo & saldo_periodo_ricl(int id, const char * codricl, const char *cod) 
{
	TSaldi_recordset_data & data = saldi_data(id);
	
	return saldo_periodo_ricl(codricl, cod);
}

const int TSaldi_conti_recordset::nper() const
{
	return saldi_data(_id).nper();
}

const TDate & TSaldi_conti_recordset::from(int n) const
{
	return n < nper() ? (const TDate &) saldi_data(_id).from()[n] : botime ;
}

const TDate & TSaldi_conti_recordset::to(int n) const
{
	return n < nper() ? (const TDate &) saldi_data(_id).to()[n] : botime ;
}

bool TSaldi_conti_recordset::provv() const
{
	return saldi_data(_id).provv();
}

void TSaldi_conti_recordset::requery()
{
	saldi_data(_id).saldi().destroy();
	TISAM_recordset::requery();
}

void TSaldi_conti_recordset::set_custom_columns()
{
	TRecordset_column_info c;

	c._type = _realfld;
	c._width = 18;
	for (int i = 0; i < nper(); i++)
	{
		if (_sel_columns > 0)
		{
			c._name.format("SALDOINI[%d]", i);
			add_column_info(c);
			c._name.format("PDARE[%d]", i);
			add_column_info(c);
			c._name.format("PAVERE[%d]", i);
			add_column_info(c);
		}
		c._name.format("SALDO[%d]", i);
		add_column_info(c);
	}
}

HIDDEN bool non_zero(const TRelation * r)
{
	TLocalisamfile & pcon = r->lfile(LF_PCON);
	const char tcf = pcon.get_char(PCN_TMCF);
	const int gruppo = pcon.get_int(PCN_GRUPPO);
	const int conto = pcon.get_int(PCN_CONTO);
	const long sottoconto = pcon.get_long(PCN_SOTTOCONTO);
	const TSaldo_periodo & s = saldo_periodo_conto(tcf, gruppo, conto, sottoconto);

	return s.movimentato() || !s.is_zero();
}

TCursor* TSaldi_conti_recordset::cursor() const
{
	bool new_cursor = !valid_cursor();
	TCursor * c = TISAM_recordset::cursor();

	if (new_cursor)
	{
		if (!_all)
			c->set_filterfunction(non_zero);
		((TSaldi_conti_recordset *) this)->set_custom_columns();
	}
	return c;
}

const TSaldo_periodo & TSaldi_conti_recordset::saldo_periodo() 
{
  const int gruppo = get(PCN_GRUPPO).as_int();
	const int conto = get(PCN_CONTO).as_int();
  const long sottoconto = get(PCN_SOTTOCONTO).as_int();
	char tcf = get(PCN_TMCF).as_string()[0];

	return saldo_periodo_conto(tcf, gruppo, conto, sottoconto);
}

const TVariant& TSaldi_conti_recordset::get_field(int logic, const char* field) const
{
	const TString80 fname(field);

	if (_sel_columns > 0)
	{
		if (fname.starts_with("SALDOINI"))
			return ((TSaldi_conti_recordset *)this)->saldo_periodo().saldoini(atoi(fname.mid(9)));
		else
			if (fname.starts_with("PAVERE"))
				return ((TSaldi_conti_recordset *)this)->saldo_periodo().pavere(atoi(fname.mid(7)));
			else
				if (fname.starts_with("PDARE"))
					return ((TSaldi_conti_recordset *)this)->saldo_periodo().pdare(atoi(fname.mid(6)));
	}
	if (fname.starts_with("SALDO"))
		return ((TSaldi_conti_recordset *)this)->saldo_periodo().saldo(atoi(fname.mid(6)));
	else
		if (fname.starts_with("INDBIL"))
		{
			TVariant & var = get_tmp_var();
			TString16 key;	key.format("%ld|%ld", get(PCN_GRUPPO).as_int(), get(PCN_CONTO).as_int());
			const int indbil = atoi(cache().get(LF_PCON, key, PCN_INDBIL));

			var = indbil;
			return var;
		}

	if (fname == PCN_GRUPPO ||	fname ==PCN_CONTO || fname ==PCN_SOTTOCONTO)
	{
		TVariant & val = (TVariant &) TISAM_recordset::get_field(logic, field);
		const int len = cursor()->relation()->lfile().curr().length(fname);
		TString v(val.as_string());

		v.lpad(len, '0');
		val = v;
		return val;
	}
	return TISAM_recordset::get_field(logic, field);
}

void TSaldi_conti_recordset::set_fromto()
{
	TSaldi_recordset_data & data = saldi_data(_id);
	TDate dal = (TDate &) data.from()[0];

	data.from().destroy();
	if (data.nper() <= 0)
		data.nper() = 1;
	if (dal.ok())
	{
    const TRectype & per = cache().get("&PER", _codper);

		for (int i = 0; i < data.nper(); i++)
		{
	    TDate al = dal; 
			al += per.get_int("I0");
			al += per.get_int("I1") * 7;
			al.addmonth(per.get_int("I2"));
			al.addyear(per.get_int("I3"));
			if (al > dal)
				--al;
			else
				al = dal;
			data.from().add(dal);
			data.to().add(al);
			dal = ++al;	
		}
  }
}

TSaldi_conti_recordset::TSaldi_conti_recordset(const char * codper, int	nper, const TDate & dal, int sel_columns, bool provv, bool all, bool prog,
																							 const TString& sql)
											: TISAM_recordset(sql), _codper(codper), _sel_columns(sel_columns), _all(all)
{
	_id = __shuttle.add(new TSaldi_recordset_data);

	TSaldi_recordset_data & data = saldi_data(_id);

	data.nper() = nper;
	data.provv() = provv;
	data.prog() = prog;
	data.from().destroy();
	data.to().destroy();
	data.from().add(dal);
	set_fromto();
	if (sql.blank())
	{
		TString query;
		query << "USE " << LF_PCON;
		query << "\nDISPLAY \"Gruppo\" GRUPPO\nDISPLAY \"Conto\" CONTO\nDISPLAY \"Sottoconto\" SOTTOCONTO\nDISPLAY \"Descrizione\" DESCR\nDISPLAY \"Indicatore Bil.\" INDBIL\n";
		set(query);
	}
	else
	{
		const int p = sql.find("RICLCG");

		if (p > 0)
		{
			TString query(sql.left(p));

			query << LF_PCON << sql.mid(p + 6);
			set(query);
		}
	}
}

TSaldi_conti_recordset::TSaldi_conti_recordset(const TMask& m, const TString& sql) : TISAM_recordset(sql)
{
	_id = __shuttle.add(new TSaldi_recordset_data);

	TSaldi_recordset_data & data = saldi_data(_id);
	const int items = m.fields();

	data.from().destroy();
	data.to().destroy();
	_codper.cut(0);
	_all = true;
	_sel_columns = 0;
  for (short i = 0; i < items; i++)
  {
    const TMask_field &f = m.fld(i);
		const TFieldref* fld = f.field();

    if (fld != NULL)
    {
      TString80 fldname=fld->name();
			
			if (fldname.starts_with("PER"))
				_codper = f.get();
			else
				if (fldname.starts_with("NPER"))
					data.nper() = f.get_long();
				else
					if (fldname.starts_with("DAL"))
						data.from().add(new TDate(f.get()), 0);
					else
						if (fldname.starts_with("PROVV"))
							data.provv() = f.get().full();
						else
							if (fldname.starts_with("ALL"))
								_all = f.get().full();
							else
								if (fldname.starts_with("COLTYPE"))
									_sel_columns = atoi(f.get());
								else
									if (fldname.starts_with("PROG"))
										data.prog() = f.get().full();
    }
  }
	set_fromto();
	if (sql.blank())
	{
		TString query("USE ");

		query << LF_PCON;
		query << "\nDISPLAY \"Gruppo\" GRUPPO\nDISPLAY \"Conto\" CONTO\nDISPLAY \"Sottoconto\" SOTTOCONTO\nDISPLAY \"Descrizione\" DESCR\nDISPLAY \"Indicatore Bil.\" INDBIL\n";
		set(query);
	}
	else
	{
		const int p = sql.find("RICLCG");

		if (p > 0)
		{
			TString query(sql.left(p));

			query << LF_PCON << sql.mid(p + 6);
			set(query);
		}
	}
}

TSaldi_conti_recordset::~TSaldi_conti_recordset()
{
	__shuttle.destroy(_id);
}

void TSaldi_ricl_recordset::set_custom_columns()
{
	TRecordset_column_info c;

	c._type = _longfld;
	c._name = "INDBIL";
	c._width = 1;
	add_column_info(c);

	c._type = _realfld;
	c._width = 18;
	for (int i = 0; i < nper(); i++)
	{
		if (sel_columns() > 0)
		{
			c._name.format("SALDOINI[%d]", i);
			add_column_info(c);
			c._name.format("PDARE[%d]", i);
			add_column_info(c);
			c._name.format("PAVERE[%d]", i);
			add_column_info(c);
		}
		c._name.format("SALDO[%d]", i);
		add_column_info(c);
	}
}

const TSaldo_periodo & TSaldi_ricl_recordset::saldo_periodo() 
{
	const TString16 cod = get("CODTAB").as_string();

	return saldo_periodo_ricl(_codricl, cod);
}

const TVariant& TSaldi_ricl_recordset::get_field(int logic, const char* field) const
{
	const TString80 fname(field);

	if (sel_columns() > 0)
	{
		if (fname.starts_with("SALDOINI"))
			return ((TSaldi_ricl_recordset *)this)->saldo_periodo().saldoini(atoi(fname.mid(9)));
		else
			if (fname.starts_with("PAVERE"))
				return ((TSaldi_ricl_recordset *)this)->saldo_periodo().pavere(atoi(fname.mid(7)));
			else
				if (fname.starts_with("PDARE"))
					return ((TSaldi_ricl_recordset *)this)->saldo_periodo().pdare(atoi(fname.mid(6)));
	}
	if (fname.starts_with("SALDO"))
		return ((TSaldi_ricl_recordset *)this)->saldo_periodo().saldo(atoi(fname.mid(6)));
	else
		if (fname.starts_with("INDBIL"))
			return get("I0");

	return TISAM_recordset::get_field(logic, field);
}
HIDDEN bool non_zero_ricl(const TRelation * r)
{
	TSaldi_recordset_data & data = saldi_data();
	const TString16  codricl = data.codricl();
	const TString & table = data.table();
	TLocalisamfile & tab = r->lfile(table);
	const TString16 cod = tab.get("CODTAB");
	const TSaldo_periodo & s = saldo_periodo_ricl(codricl, cod);

	return s.movimentato() || !s.is_zero();
}

TCursor* TSaldi_ricl_recordset::cursor() const
{
	bool new_cursor = !valid_cursor();
	TCursor * c = TISAM_recordset::cursor();

	if (new_cursor)
	{
		if (!_all)
			c->set_filterfunction(non_zero_ricl);
		((TSaldi_ricl_recordset *) this)->set_custom_columns();
	}
	return c;
}
bool TSaldi_ricl_recordset::provv() const
{
	return saldi_data(_id).provv();
}

const int TSaldi_ricl_recordset::nper() const
{
	return saldi_data(_id).nper();
}

const TDate & TSaldi_ricl_recordset::from(int n) const
{
	return (const TDate &) saldi_data(_id).from()[n];
}

const TDate & TSaldi_ricl_recordset::to(int n) const
{
	return (const TDate &) saldi_data(_id).to()[n] ;
}

void TSaldi_ricl_recordset::requery()
{
	saldi_data(_id).saldi().destroy();
	TISAM_recordset::requery();
}
void TSaldi_ricl_recordset::set_fromto()
{
	TSaldi_recordset_data & data = saldi_data(_id);
	TDate dal = (TDate &) data.from()[0];

	data.from().destroy();
	if (data.nper() <= 0)
		data.nper() = 1;
	if (dal.ok())
	{
    const TRectype & per = cache().get("&PER", _codper);

		for (int i = 0; i < data.nper(); i++)
		{
	    TDate al = dal; 
			al += per.get_int("I0");
			al += per.get_int("I1") * 7;
			al.addmonth(per.get_int("I2"));
			al.addyear(per.get_int("I3"));
			if (al > dal)
				--al;
			else
				al = dal;
			data.from().add(dal);
			data.to().add(al);
			dal = ++al;	
		}
  }
}

TSaldi_ricl_recordset::TSaldi_ricl_recordset(const char * codricl, const char * codper, int	nper, const TDate & dal, int sel_columns, bool provv,
																						 bool all, bool prog, const TString& sql) : TISAM_recordset(sql), _codricl(codricl), _all(all), _prog(prog), _sel_columns(sel_columns)
{
	_id = __shuttle.add(new TSaldi_recordset_data);

	TSaldi_recordset_data & data = saldi_data(_id);
	TString8 table;

	data.from().destroy();
	data.to().destroy();
	if (_codricl.starts_with("RI"))
			table = "&RCO";
	else
		if (_codricl.starts_with("TS"))
			table = "&TCTCO";
		else
			if (_codricl.starts_with("ZU"))
				table << "&TCZCO";
	data.codricl() = _codricl;
	data.table() = table;
	data.prog() = _prog;
	set_fromto();
	if (sql.blank())
	{
		TString query;

		query << "USE " << table << "\nDISPLAY \"Codice\" CODTAB\nDISPLAY \"Descrizione\" S0\n";
		set(query);
	}
	else
	{
		const int p = sql.find("RICLCG");

		if (p > 0)
		{
			TString query(sql.left(p));

			query << table << sql.mid(p + 6);
			set(query);
		}
	}
}

TSaldi_ricl_recordset::TSaldi_ricl_recordset(const TMask& m, const TString& sql) : TISAM_recordset(sql)
{
	_id = __shuttle.add(new TSaldi_recordset_data);

	TSaldi_recordset_data & data = saldi_data(_id);
	const int items = m.fields();

	data.from().destroy();
	data.to().destroy();
	_codricl.cut(0);
	_codper.cut(0);
	_all = true;
	_sel_columns = 0;
  for (short i = 0; i < items; i++)
  {
    const TMask_field &f = m.fld(i);
		const TFieldref* fld = f.field();

    if (fld != NULL)
    {
      TString80 fldname=fld->name();
			
			if (fldname.starts_with("TRICL"))
				_codricl = f.get();
			else
				if (fldname.starts_with("RICL"))
					_codricl << f.get();
					if (fldname.starts_with("PER"))
						_codper = f.get();
					else
						if (fldname.starts_with("NPER"))
							data.nper() = f.get_long();
						else
							if (fldname.starts_with("DAL"))
								data.from().add(new TDate(f.get()), 0);
							else
								if (fldname.starts_with("PROVV"))
									data.provv() = f.get().full();
								else
									if (fldname.starts_with("ALL"))
										_all = f.get().full();
									else
										if (fldname.starts_with("COLTYPE"))
											_sel_columns = atoi(f.get());
										else
											if (fldname.starts_with("PROG"))
												_prog = f.get().full();
		}
	}
	
	TString8 table;

	if (_codricl.starts_with("RI"))
			table = "&RCO";
	else
		if (_codricl.starts_with("TS"))
			table = "&TCTCO";
		else
			if (_codricl.starts_with("ZU"))
				table << "&TCZCO";
	data.codricl() = _codricl;
	data.table() = table;
	data.prog() = _prog;
	set_fromto();
	if (sql.blank())
	{
		TString query;

		query << "USE " << table << "\nDISPLAY \"Codice\" CODTAB\nDISPLAY \"Descrizione\" S0\n";
		set(query);
	}
	else
	{
		const int p = sql.find("RICLCG");

		if (p > 0)
		{
			TString query(sql.left(p));

			query << table << sql.mid(p + 6);
			set(query);
		}
	}
}

TSaldi_ricl_recordset::~TSaldi_ricl_recordset()
{
	__shuttle.destroy(_id);
}
///////////////////////////////////////////////////////////
// TDocument_report
///////////////////////////////////////////////////////////

KEY TRicl_report::run_form(TMask& m)
{
	KEY key = TReport::run_form(m);
	
	if (key == K_ENTER)
	{
		const int items = m.fields();
		
		_codricl.cut(0);
		_codper.cut(0);
		_nper = 0;
		_dal = botime;
		_provv = false;
		_all = true;
		_sel_columns = 0;
		for (short i = 0; i < items; i++)
		{
			const TMask_field &f = m.fld(i);
			const TFieldref* fld = f.field();

			if (fld != NULL)
			{
				TString80 fldname=fld->name();
				
				if (fldname.starts_with("TRICL"))
					_codricl = f.get();
				else
					if (fldname.starts_with("RICL"))
						_codricl << f.get();
						if (fldname.starts_with("PER"))
							_codper = f.get();
						else
							if (fldname.starts_with("NPER"))
								_nper = f.get_long();
							else
								if (fldname.starts_with("DAL"))
									_dal = TDate(f.get());
								else
									if (fldname.starts_with("PROVV"))
										_provv = f.get().full();
									else
										if (fldname.starts_with("ALL"))
											_all = f.get().full();
										else
											if (fldname.starts_with("COLTYPE"))
												_sel_columns = atoi(f.get());
											else
												if (fldname.starts_with("PROG"))
													_prog = f.get().full();
			}
		}
	}
  
  return key;
}
bool TRicl_report::set_recordset(const TString& query)
{
	if (query.find("RICLCG") > 0)
	{
		if (_codricl.full())
			return TReport::set_recordset(new TSaldi_ricl_recordset(_codricl, _codper, _nper, _dal, _sel_columns, _provv, _all, _prog, query));
		else
			return TReport::set_recordset(new TSaldi_conti_recordset(_codper, _nper, _dal, _sel_columns, _provv, _all, _prog, query));
	}
	return TReport::set_recordset(query);
}

bool TRicl_report::load(const char* name)
{
  const bool ok = TReport::load(name);
  if (ok)
  {
    // Purtroppo il recordset delle sottosezioni deve essere reimpostato a mano
    for (int i = 11; i <= 999; i++)
    {
      TReport_section* sec = find_section('B', i);
      if (sec != NULL)
      {
        TRecordset* recset = sec->recordset();
        if (recset != NULL)
        {
          const TString use = recset->query_text();

					if (use.find("RICLCG") > 0)
					{
						if (_codricl.full())
							return TReport::set_recordset(new TSaldi_ricl_recordset(_codricl, _codper, _nper, _dal, _sel_columns, _provv, _all, _prog, use));
						else
							return TReport::set_recordset(new TSaldi_conti_recordset(_codper, _nper, _dal, _sel_columns, _provv, _all, _prog, use));
	          sec->set_recordset(recset);
					}
        }
      }
    }
  }
  return ok;
}

size_t TRicl_report::get_usr_words(TString_array& words) const
{
  TReport::get_usr_words(words);
  
  const char* const name[] = { NULL };

  ((TRicl_report*)this)->_first_msg = words.items(); // Calcola il primo numero disponibile
  for (size_t i = 0; name[i] != NULL; i++)
    words.add(name[i]);
  
  return words.items();
}

bool TRicl_report::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
{
  if (opcode < _first_msg)
    return TReport::execute_usr_word(opcode, stack);
  opcode -= _first_msg;
  switch (opcode)
  {
		case 0:
	  default: break;
  }

  while (!stack.pop().is_null());  // Svuota eventuali parametri variabili inutilizzati

  return true;
}