#include <applicat.h>
#include <automask.h>
#include <execp.h>
#include <progind.h>
#include <recarray.h>
#include <recset.h>
#include <relation.h>
#include <reprint.h>

#include "../cg/cglib01.h"

#include "ammce.h"
#include "cespi.h"
#include "movce.h"
#include "salce.h"
#include "celib.h"

#include "ce4.h"
#include "ce4300.h"

////////////////////////////////////////////////////////
//	MASCHERA
////////////////////////////////////////////////////////
class TStampa_proiez_ammo_mask : public TAutomask
{
protected:
  bool on_field_event(TOperable_field& o, TField_event e, long jolly);

public:
  TStampa_proiez_ammo_mask();
  virtual ~TStampa_proiez_ammo_mask() {}
};


bool TStampa_proiez_ammo_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  bool ok = true;
  switch (o.dlg())
  {
  case F_FROM_CAT:
  case F_D_FROM_CAT:
  case F_TO_CAT:
  case F_D_TO_CAT:
    {
      TDitta_cespiti& dc = ditta_cespiti();
      ok = dc.on_category_event(o, e, jolly);
    }
    break;

	case F_ESERCIZIO:
  case F_GRUPPO:
  case F_SPECIE:
    if (e == fe_init || e == fe_modify)
    {
      const TString& esercizio = get(F_ESERCIZIO);
      const TString& gruppo = get(F_GRUPPO);
      const TString& specie = get(F_SPECIE);
      TString16 key; key << esercizio << gruppo << specie;
      TRelation ccb("CCB");
      ccb.curr().put("CODTAB", key);
      if (ccb.read() == NOERR)
        autoload(ccb);
    }
    break;
  default: break;
  }
  return ok;
}


TStampa_proiez_ammo_mask::TStampa_proiez_ammo_mask()
								:TAutomask("ce4300")
{}


///////////////////////////////////////////////////////////////
//	RECORDSET
///////////////////////////////////////////////////////////////

class TStampa_proiez_ammo_recordset : public TISAM_recordset
{
public:
  void set_filter(const TStampa_proiez_ammo_mask& msk);
  TStampa_proiez_ammo_recordset(const TString& sql) : TISAM_recordset(sql) { }
};

static const TStampa_proiez_ammo_recordset* myself = NULL;

//metodo per caricare i valori nel recordset dalla maschera...fighissimo!!
void TStampa_proiez_ammo_recordset::set_filter(const TStampa_proiez_ammo_mask& msk)
{
	const TString& gruppo = msk.get(F_GRUPPO);
	const TString& specie = msk.get(F_SPECIE);
	TString8 attivita;
	attivita.format("%-2s%-4s", (const char*)gruppo, (const char*)specie);

	const TString& dacat = msk.get(F_FROM_CAT);
	const TString& acat = msk.get(F_TO_CAT);
	TString query = "USE %CAC";

	query << " SELECT ((CODTAB[1,6]='      ')||(CODTAB[1,6]='" << attivita << "'))";
	if (dacat.full() || acat.full())
	{
		
		if (dacat == acat)
			query << "&&(CODTAB[7,8]=='" << dacat << "')";
		else
		{
			if (dacat.full())
				query << "&&(CODTAB[7,8]>='" << dacat << "')";
			if (acat.full())
				query << "&&(CODTAB[7,8]<='" << acat << "')";
		}
	}
	query << "\nBY I0 CODTAB[7,8]";
	set(query);	//setta la nuova query nel report
}


////////////////////////////////////////////////////////
//	REPORT
////////////////////////////////////////////////////////
class TStampa_proiez_ammo_rep : public TReport
{
	int _anno;
	//Clamoroso TAssocarray che conterra' tutti i valori dei record di CESPI utili al completamento..
	//..della faticosa stampa..
	TAssoc_array _cat;

protected:
	virtual bool get_usr_val(const TString& name, TVariant& var) const;
	void add_value (const int codcat, const char* field, const real& value);
	real get_value (const int codcat, const char* field) const;

public:
	void set_filter(const TStampa_proiez_ammo_mask& msk);
};


void TStampa_proiez_ammo_rep::add_value (const int codcat, const char* field, const real& value)
{
	TString4 key;
	key << codcat;

	TAssoc_array* cat = (TAssoc_array*)_cat.objptr(key);
	if (cat == NULL)
	{
		cat = new TAssoc_array;
		_cat.add(key, cat);
	}
	real* val = (real*)cat->objptr(field);
	if (val == NULL)
	{
		val = new real;
		cat->add(field, val);
	}
	*val += value;
}


real TStampa_proiez_ammo_rep::get_value (const int codcat, const char* field) const
{
	TString4 key;
	key << codcat;

	TAssoc_array* cat = (TAssoc_array*)_cat.objptr(key);
	if (cat != NULL)
	{
  	real* val = (real*)cat->objptr(field);
	  if (val != NULL)
			return *val;
	}
	return ZERO;
}


void TStampa_proiez_ammo_rep::set_filter(const TStampa_proiez_ammo_mask& msk)
{
  _anno = msk.get_int(F_ESERCIZIO);
	((TStampa_proiez_ammo_recordset*) recordset())->set_filter(msk);

	_cat.destroy();

	//Si vuole creare una lista di tutti i cespiti che ricadono nei parametri gr/sp/cat della..
	//..maschera di selezione, che verra' poi utilizzato per calcolare i valori del costo di tali..
	//..cespiti riuniti nella categoria di appartenenza
	TRelation rel_cespi(LF_CESPI);
	TRectype darec_cespi(LF_CESPI), arec_cespi(LF_CESPI);
	darec_cespi.put(CESPI_CODCGRA, msk.get(F_GRUPPO));
	darec_cespi.put(CESPI_CODSPA, msk.get(F_SPECIE));
	darec_cespi.put(CESPI_CODCAT, msk.get(F_FROM_CAT));

	arec_cespi = darec_cespi;
	arec_cespi.put(CESPI_CODCAT, msk.get(F_TO_CAT));

	//Dalla lista cespiti deve risalire ai costi, agli ammortamenti e alle alienazioni;..
	//..quindi servono i files collegati..
	TLocalisamfile salce(LF_SALCE);
	TLocalisamfile ammce(LF_AMMCE);

	//ISAM query per trovare su MOVCE i movimenti relativi al cespite corrente nell'esercizio selezionato
	TString query;
	TEsercizi_contabili esc;
  const TDate& dataini = esc[_anno].inizio();
	const TDate& datafine = esc[_anno].fine();
	query.format("USE MOVCE KEY 2 SELECT NUM(ANSI(DTMOV)>=%ld)&&NUM(ANSI(DTMOV)<=%ld)\nFROM IDCESPITE=#CESPITE\nTO IDCESPITE=#CESPITE",
							 dataini.date2ansi(), datafine.date2ansi());
	TISAM_recordset movce(query);

	//Ciclo principale per riempire _cat, assoc_array di assoc_array che sara' poi scandito in fase di creazione report
	//Il metodo add_value e' quello che effettivamente aggiunge i valori a _cat
	TCursor cur_cespi(&rel_cespi, "", 2, &darec_cespi, &arec_cespi);
	const TRecnotype num = cur_cespi.items();
	TProgind pi(num, "Calcolo proiezione ammortamenti...");
	for (cur_cespi = 0; cur_cespi.pos() < num; ++cur_cespi)
	{
		pi.addstatus(1);

		real costo_ini, costo_fin, alien, famm;

		//Colonna COSTO
		const TString idcespite = rel_cespi.curr().get(CESPI_IDCESPITE);
		const int codcat = rel_cespi.curr().get_int(CESPI_CODCAT);
		salce.put(SALCE_IDCESPITE, idcespite);
		salce.put(SALCE_CODES, _anno);
		salce.put(SALCE_TPSALDO, 1);
		if (salce.read() == NOERR)
		{
			//costo ad inizio esercizio (=0 nel caso di acquisto cespite nell'anno in corso)
			costo_ini = salce.get_real(SALCE_CSTO);
			add_value(codcat, SALCE_CSTO, costo_ini);
			//costo a fine esercizio (=0 nel caso di vendita cespite nell'anno in corso)
			salce.next();
			costo_fin = salce.get_real(SALCE_CSTO);
		}

		//Colonna ALIENAZIONI
		//cerca tutti i movimenti di vendita relativi al cespite corrente all'interno dell'esercizio.. 
		//..selezionato sulla maschera;somma i loro importi in modo da ricavare l'importo complessivo..
		//..di tutti
		movce.set_var("#CESPITE", TVariant(idcespite));		//assegna il vero valore dell'idcespite alla query
		for (TRecnotype i = 0; movce.move_to(i); i++)
		{
			const real vendita = movce.get(MOVCE_IMPVEN).as_real();
			add_value(codcat, MOVCE_IMPVEN, vendita);
			alien += vendita;
		}

		//Colonna FAMM (fondo ammortamento)
		ammce.put(AMMCE_IDCESPITE, idcespite);
		ammce.put(AMMCE_CODES, _anno);
		ammce.put(AMMCE_TPSALDO, 1);	//tiposaldo iniziale
		ammce.put(AMMCE_TPAMM, 1);		//tipoamm fiscale
		if (ammce.read() == NOERR)
		{
			famm += ammce.get_real(AMMCE_QNOR);
			famm += ammce.get_real(AMMCE_QACC);
			famm += ammce.get_real(AMMCE_QANT);
			add_value(codcat, "AMMO0", famm);
		}

		//Colonna QAMM
		//Per questi ci vuole un tiposaldo diverso
		ammce.put(AMMCE_TPSALDO, 2);	//tiposaldo finale
		if (ammce.read() == NOERR)
		{
			real qamm;
			qamm += ammce.get_real(AMMCE_QNOR);
			qamm += ammce.get_real(AMMCE_QACC);
			qamm += ammce.get_real(AMMCE_QANT);
			add_value(codcat, "AMMO1", qamm);

			//Colonne degli ammortamenti
			//Si calcolano in questo modo perche' si calcolano cespite x cespite;si usa costo_fin perche' e'..
			//..quello che serve nel futuro!
			real residuo = costo_fin - alien - famm - qamm;	//qamm e' AMMO1
			TString8 ammo;
			for (int a = 2; a <= 5 && residuo > ZERO; a++)
			{
        ammo.format("AMMO%d", a);
        if (qamm >= residuo)
				{
					add_value(codcat, ammo, residuo);
					residuo = ZERO;
				}
				else
				{
					add_value(codcat, ammo, qamm);
					residuo -= qamm;
				}
			}
			if (residuo > ZERO)
				add_value(codcat, "AMMOX", residuo);
		}

	}	//for(cur_cespi...

}

//metodo per il calcolo dei campi da calcolare (ma va'!) nel report
bool TStampa_proiez_ammo_rep::get_usr_val(const TString& name, TVariant& var) const
{
	const TRecordset& recset = *recordset();
	const int codcat = atoi(recset.get("CODTAB").as_string().mid(6, 2));

	if (name == "#ANNOES")
	{
		var.set(_anno);
		return true;
	}
	if (name == "#FINESCPREC")
	{
		TEsercizi_contabili esc;
		TDate dal, al;
		esc.code2range(_anno, dal, al);
		var.set(dal - 1L);
		return true;
	}
	if (name == "#COSTO")	//costo
	{		
		var = get_value(codcat, SALCE_CSTO);
		return true;
	}
	if (name == "#ALIENAZ")	//movimenti di vendita
	{
		var = get_value(codcat, MOVCE_IMPVEN);
		return true;
	}
	if (name.starts_with("#AMMO"))	//fondi ammortamento
	{
		var = get_value(codcat, name.mid(1));
		return true;
	}

	return TReport::get_usr_val(name, var);
}

////////////////////////////////////////////////////////
//	APPLICAZIONE
////////////////////////////////////////////////////////
class TStampa_proiez_ammo : public TSkeleton_application
{
protected:
  virtual void main_loop();
};


void TStampa_proiez_ammo::main_loop()
{
	TStampa_proiez_ammo_mask mask;
  while (mask.run() == K_ENTER)
  {
		//report e book dei report
		TReport_book book;
		TStampa_proiez_ammo_rep rep;
		rep.load("ce4300a");

		rep.set_filter(mask);
		book.add(rep);

		book.print_or_preview();	//stampa il book dei report
	}
}

int ce4300(int argc, char* argv[])
{
  TStampa_proiez_ammo a;
  a.run(argc, argv, TR("Stampa proiezione ammortamenti cespiti"));
  return 0;
}