#include <applicat.h>
#include <mask.h>
#include <printer.h>
#include <progind.h>
#include <relation.h>
#include <tabutil.h>
#include <urldefid.h>
#include <utility.h>

#include "at3.h"

// nomi campi maschera
#include "at3500a.h"
          
// nomi dei campi
#include "soggetti.h"
#include "donaz.h"
#include "atstatd.h"
#include "sezioni.h"

// classe per la definizione di una riga di statistica
class TRigaG : public TObject
{                             
	TDate 				_data;
	TArray				_valori;

protected:
	const TRigaG& copy(const TRigaG& riga);
public:
	const TDate data() const { return _data; }
	TObject* dup() const { return new TRigaG(*this); }
	const TRigaG& operator = (const TRigaG& riga);
	const real& operator [] (int colonna) const;
	void aggiorna_valore(int colonna, const real& numero) ;
	void azzera_valori();
	// costruttore
	TRigaG(TDate data) {_data = data;}
	// costruttore di copia
	TRigaG(const TRigaG& riga)  { copy(riga); }
	virtual ~TRigaG() {};
};

const TRigaG& TRigaG::copy(const TRigaG& riga)
{
	_data = riga._data;
	_valori = riga._valori;
	return (*this);
}

const TRigaG& TRigaG::operator = (const TRigaG& riga)
{
	copy(riga);
	return (*this);
}

const real& TRigaG::operator [] (int colonna) const
{
	real* valore = (real*)_valori.objptr(colonna);
	if (valore == NULL)
		return ZERO;
	else
		return *valore;		
}

void TRigaG::aggiorna_valore(int colonna, const real& numero)
{
	real* valore = (real*)_valori.objptr(colonna);
	if (valore == NULL)
		_valori.add(new real(numero), colonna);
	else
		*valore += numero;
}
  
void TRigaG::azzera_valori()
{
	_valori.destroy();
}

class TRiepilogoGiornaliero : public TApplication
{
	TMask*					_msk;
	TRelation*   		_rel;
	TCursor*				_cur;
	TLocalisamfile* _sezioni;
	TLocalisamfile* _soggetti;
	TLocalisamfile* _donaz;
	TLocalisamfile* _atstatd;
	bool						_primedon;
	TDate						_dataini, _datafin;
	TAssoc_array*		_colonne;
	TArray					_righe;	// array per riepilogo donazioni
	TArray					_righe_prime; // array per riepilogo prime don		
	TString16				_sezini, _sotini, _sezfin, _sotfin, _punto;
	char						_suddivisa;

protected:
	virtual bool create();
	virtual bool destroy();
  virtual bool menu(MENU_TAG m);
	virtual TMask& get_mask() { return *_msk; }
	virtual TRelation* get_relation() const { return _rel; }
	int data2row(const TDate data) { return ((int) (data-_dataini)); }
	bool riepilogo();
	bool stampa();
	bool crea_colonne();
	bool crea_righe();
	void azzera_righe();
	void stampa_sezione(const TString16 codsez, const TString16 codsot);
	void stampa_punto(const TString16 punto);
	void stampa_tutto();
	void crea_intestazione(const bool primedon = FALSE);
public:
	TRiepilogoGiornaliero() {}
	
};

HIDDEN inline TRiepilogoGiornaliero& app() { return (TRiepilogoGiornaliero&) main_app(); }

bool TRiepilogoGiornaliero::crea_colonne()
{                   
	_colonne->destroy();
	TTable tdn("TDN");
	real contatore(ZERO);
	for (tdn.first(); !tdn.eof(); tdn.next())
	{ 
		real* oggetto = new real(contatore);                                
		_colonne->add((const char*)tdn.get("CODTAB"),(TObject*)oggetto);
		contatore+=1;
	}		
	return !tdn.empty();
}

bool TRiepilogoGiornaliero::crea_righe()
{                     
	TDate data = _dataini;
	while (data<=_datafin)
	{            
		_righe.add(new TRigaG(data), data2row(data));
		if (_primedon)
			_righe_prime.add(new TRigaG(data), data2row(data));
		++data;
	}		
	return _righe.items()>0;	
}

bool TRiepilogoGiornaliero::create()
{
	TApplication::create();
	_msk = new TMask("at3500a");
	_rel = new TRelation(LF_DONAZ);
  _rel->add(LF_SOGGETTI, "CODICE==CODICE");
  _soggetti = new TLocalisamfile(LF_SOGGETTI);
	_donaz = new TLocalisamfile(LF_DONAZ);
	_atstatd = new TLocalisamfile(LF_ATSTATD);	
	_sezioni = new TLocalisamfile(LF_SEZIONI);
	_colonne = new TAssoc_array();
  dispatch_e_menu(BAR_ITEM(1));
	return TRUE;
}	

bool TRiepilogoGiornaliero::destroy()	
{
	delete _colonne;
	delete _sezioni;
	delete _atstatd;
	delete _donaz;
	delete _soggetti;
	delete _rel;
	delete _msk;
	return TApplication::destroy();
}

bool TRiepilogoGiornaliero::menu(MENU_TAG m)
{ 
	TMask& msk = get_mask();
	KEY tasto;
 	tasto = msk.run();
 	if (tasto == K_ENTER)
 	{
		_dataini = msk.get(F_DATAINI); 		
		_datafin = msk.get(F_DATAFIN); 		
		_primedon = msk.get_bool(F_PRIMEDON);
		_suddivisa = msk.get(F_SUDDIVISA)[0];
		_punto = msk.get(F_PUNTO);
 		_sezini = msk.get(F_SEZINI);
 		_sotini = msk.get(F_SOTINI);
 		_sezfin = msk.get(F_SEZFIN);
 		_sotfin = msk.get(F_SOTFIN);
		if (riepilogo())
			stampa();
 	}
 	return FALSE;
}  

void TRiepilogoGiornaliero::crea_intestazione(const bool primedon)
{ 
	TPrintrow row;
	TString256 sep;
	sep = "GIORNALIERO DONAZIONI";
	if (_dataini.ok())
	{
		sep << " dal ";
		sep << _dataini.string();
	}
	if (_datafin.ok())
	{
		sep << " al ";
		sep << _datafin.string();
	}
	sep.center_just(80);
	row.put(sep);
  row.put("@>", 1);
  row.put("Pag. @#", 70);
  printer().setheaderline(2, row);
  row.reset();
	if (primedon)
	{
		sep = "RIEPILOGO PRIME DONAZIONI ";
		sep.center_just(80);
		row.put(sep);
	}	
 	printer().setheaderline(3, row);	  
  row.reset();
  sep = "Data ";
	TTable tdn("TDN");
	int pos = 27;
	for (tdn.first(); !tdn.eof(); tdn.next())
	{ 
		sep.overwrite((const char*)tdn.get("CODTAB"),pos);
		pos = pos+10;
	}		
	sep.overwrite("Totale",pos);	
	row.put(sep);
	printer().setheaderline(5, row);  
	sep = "";
	sep.fill('-',80);
	row.reset();
	row.put(sep);
	printer().setheaderline(6, row);
}

bool TRiepilogoGiornaliero::stampa()
{ 
	if (printer().open())
	{
		crea_intestazione();
		TRelation* relstat = new TRelation(LF_ATSTATD);
		TSorted_cursor* curstat = new TSorted_cursor(relstat,"121->CODSEZ|121->CODSOT|121->GIORNO|121->TIPODON","", 1);
		if (_suddivisa == 'P')
			curstat->change_order("121->PUNTO|121->GIORNO|121->TIPODON");
		TString16 oldsez = "**";
		TString16 oldsot = "**";
		TString16 oldpunto = "**";
		double numero, numprime;
		TString16 actsez, actsot, actpunto;
		TString16 tipodon;
		TDate data;
		long last = curstat->items();
	  for ( *curstat=0; curstat->pos() < last; ++(*curstat) )
	  {
	  	actpunto = curstat->curr().get(ATS_PUNTO);
			actsez = curstat->curr().get(ATS_CODSEZ);																						  	
			actsot = curstat->curr().get(ATS_CODSOT);		
			data = curstat->curr().get_date(ATS_DATA);		
			tipodon = curstat->curr().get(ATS_TIPODON);		
			numero = (double)curstat->curr().get_int(ATS_NUMERO);		
			numprime = (double)curstat->curr().get_int(ATS_NUMPRIME);							
			if (_suddivisa == 'S')
			{
				if (actsez != oldsez || actsot != oldsot)
				{                 
					if (oldsez != "**" && oldsot != "**")
					{
						stampa_sezione(oldsez,oldsot);
						azzera_righe();
					}
					oldsez = actsez;
					oldsot = actsot;
				}				
			}
			else				
			{
				if (actpunto != oldpunto)
				{                 
					if (oldpunto != "**")
					{
						stampa_punto(oldpunto);
						azzera_righe();
					}
					oldpunto = actpunto;
				}				
			}
			TRigaG& riga = (TRigaG&)_righe[data2row(data)];
			real& colonna = (real&)_colonne->find((const char*)tipodon);
//			real colonna;
//			real * valore = (real *) _colonne->objptr((const char*)tipodon);
//			if (valore != NULL)
//				colonna = *valore;
			
			real n = numero;
			riga.aggiorna_valore((int) colonna.integer(),n);
			if (_primedon)
			{
				TRigaG& riga_prime = (TRigaG&)_righe_prime[data2row(data)];
				n = numprime;
				riga_prime.aggiorna_valore((int) colonna.integer(), n);
			}
		} 
		if (_suddivisa == 'S')
		{                            
			if (oldsez != "**" && oldsot != "**")
				stampa_sezione(oldsez,oldsot);
		}
		else
		{
			if (oldpunto != "**")
				stampa_punto(oldpunto);
		}				
		delete curstat;
		delete relstat;
		printer().close();
		return TRUE;
	}
	else
		return FALSE;		
}

void TRiepilogoGiornaliero::azzera_righe()
{
	TDate data = _dataini;
	while (data<=_datafin)
	{            
		TRigaG& riga = (TRigaG&)_righe[data2row(data)];
		riga.azzera_valori();
		if (_primedon)
		{
			TRigaG& riga_prime = (TRigaG&)_righe_prime[data2row(data)];
			riga_prime.azzera_valori();
		}
		++data;
	}		
}

void TRiepilogoGiornaliero::stampa_punto(const TString16 punto)
{ 
	TPrintrow row;
	TString256 rigastampa;
	rigastampa = "Punto: ";
	rigastampa << punto;
	rigastampa << " ";
	TTable ldn("LDN");
	ldn.put("CODTAB",punto);
	if (ldn.read() == NOERR)
		rigastampa << ldn.get("S0");
	rigastampa.center_just(80);
	row.put(rigastampa);
  printer().setheaderline(1, row);
  stampa_tutto();
}  

void TRiepilogoGiornaliero::stampa_sezione(const TString16 codsez, const TString16 codsot)
{ 
	TPrintrow row;
	TString256 rigastampa;
	rigastampa = "Sezione: ";
	rigastampa << codsez;
	if (codsot.not_empty())
	{
		rigastampa << "/";
		rigastampa << codsot;
	}		
	rigastampa << " ";
	TLocalisamfile sezioni(LF_SEZIONI);
	sezioni.setkey(1);
	sezioni.zero();
	sezioni.put(SEZ_CODSEZ,codsez);
	sezioni.put(SEZ_CODSOT,codsot);	
	if (sezioni.read() == NOERR)
	{
		TString80 den = sezioni.get(SEZ_DENSEZ);
		rigastampa << den;
		den = sezioni.get(SEZ_DENSOT);
		if (den.not_empty())
		{
			rigastampa << "/";
			rigastampa << den;
		}
	}
	rigastampa.center_just(80);
	row.put(rigastampa);
  printer().setheaderline(1, row);
  stampa_tutto();
}

void TRiepilogoGiornaliero::stampa_tutto()  
{
	crea_intestazione();
	TPrintrow row;
	TString256 rigastampa;
  TRigaG rigatotali(NULLDATE);
  TDate data = _dataini;
	real totaledata = ZERO;
	TString16 valore;
	while (data<=_datafin)
	{            
		TRigaG& riga = (TRigaG&)_righe[data2row(data)];
		row.reset();
		rigastampa = "";
		rigastampa.format("%s", (const char*)data.string()); 
		totaledata = ZERO;
		int pos = 21;
		for (int i=0;i<_colonne->items();i++)
		{                      
			rigatotali.aggiorna_valore(i,riga[i]);
			totaledata+=riga[i];
			valore = "";
			valore.format("%8s",riga[i].string(8,0));
			rigastampa.overwrite((const char*)valore, pos);
			pos = pos+10;
		}           
		valore = "";
		valore.format("%8s",totaledata.string(8,0));
		rigastampa.overwrite((const char*)valore, pos+4);
		row.put((const char*) rigastampa);
		printer().print(row);			
		++data;
	}		
	// stampa totali per sezione
	rigastampa = "";
	rigastampa.fill('-',80);
	row.reset();
	row.put(rigastampa);
	printer().print(row);
	row.reset();
	rigastampa = "";
	rigastampa = "Totale periodo";
	totaledata = ZERO;
	int pos = 21;
	for (int i=0;i<_colonne->items();i++)
	{                      
		totaledata+=rigatotali[i];
		valore = "";
		valore.format("%8s",rigatotali[i].string(8,0));
		rigastampa.overwrite((const char*)valore, pos);
		pos = pos+10;
	}           
	valore = "";
	valore.format("%8s",totaledata.string(8,0));
	rigastampa.overwrite((const char*)valore, pos+4);
	row.put((const char*) rigastampa);
	printer().print(row);			
	
	if (_primedon)
	{            
		printer().formfeed();
		crea_intestazione(TRUE);
		rigatotali.azzera_valori();
		data = _dataini;
		while (data<=_datafin)
		{            
			TRigaG& riga = (TRigaG&)_righe_prime[data2row(data)];
			row.reset();
			rigastampa = "";
			rigastampa.format("%s", (const char*)data.string()); 
			totaledata = ZERO;
			int pos = 21;
			for (int i=0;i<_colonne->items();i++)
			{                      
				rigatotali.aggiorna_valore(i,riga[i]);
				totaledata+=riga[i];
				valore = "";
				valore.format("%8s",riga[i].string(8,0));
				rigastampa.overwrite((const char*)valore, pos);
				pos = pos+10;
			}           
			valore = "";
			valore.format("%8s",totaledata.string(8,0));
			rigastampa.overwrite((const char*)valore, pos+4);
			row.put((const char*) rigastampa);
			printer().print(row);			
			++data;
		}		
		// stampa totali per sezione
		rigastampa = "";
		rigastampa.fill('-',80);
		row.reset();
		row.put(rigastampa);
		printer().print(row);
		row.reset();
		rigastampa = "";
		rigastampa = "Totale periodo";
		totaledata = ZERO;
		int pos = 21;
		for (int i=0;i<_colonne->items();i++)
		{                      
			totaledata+=rigatotali[i];
			valore = "";
			valore.format("%8s",rigatotali[i].string(8,0));
			rigastampa.overwrite((const char*)valore, pos);
			pos = pos+10;
		}           
		valore = "";
		valore.format("%8s",totaledata.string(8,0));
		rigastampa.overwrite((const char*)valore, pos+4);
		row.put((const char*) rigastampa);
		printer().print(row);			
	}
	row.reset();
  printer().setheaderline(3, row);	  
	printer().formfeed();
}

bool TRiepilogoGiornaliero::riepilogo()
{            
	if (crea_colonne() && crea_righe())
	{   
		// cancello i risultati della elaborazione precedente
		TLocalisamfile stat(LF_ATSTATD);
		for (stat.first(); !stat.eof(); stat.next())
			stat.remove();
		// filtro per data
		TRectype da(LF_DONAZ);
  	TRectype a (LF_DONAZ);
  	if (_dataini.ok())
			da.put(DON_DATADON, _dataini);
  	if (_datafin.ok())
			a.put(DON_DATADON, _datafin);
		_cur = new TCursor(_rel, "", 2, &da, &a);
		TString256 filtro = "";
		// filtro per sezione/sottogruppo
	 	if (_sezini.not_empty())
	 	{
	 		if (_sotini.not_empty())
	 		{                    
	 			filtro << "(";
	 			filtro << format("(92->CODSEZ > \"%s\")",(const char*)_sezini);
	 			filtro << " || ";
	 			filtro << "(" << format("(92->CODSEZ == \"%s\")",(const char*)_sezini);
	 			filtro << " && ";
	 			filtro << format("(92->CODSOT >= \"%s\")",(const char*)_sotini);
	 			filtro << ")";
	 			filtro << ")";
	 		}
	 		else
		 			filtro << format("(92->CODSEZ >= \"%s\")",(const char*)_sezini);
	 	}
	 	if (_sezfin.not_empty())
	 	{
 			if (filtro.not_empty())
 				filtro << " && "; 
	 	
	 		if (_sotfin.not_empty())
	 		{          
	 			filtro << "(";
	 			filtro << format("(92->CODSEZ < \"%s\")",(const char*)_sezfin);
	 			filtro << " || ";
	 			filtro << "(" << format("(92->CODSEZ == \"%s\")",(const char*)_sezfin);
	 			filtro << " && ";
	 			filtro << format("(92->CODSOT <= \"%s\")",(const char*)_sotfin);
	 			filtro << ")";
	 			filtro << ")";
	 		}
	 		else
	 			filtro << format("(92->CODSEZ <= \"%s\")",(const char*)_sezfin);
		}
		if (_punto.not_empty())
		{
  		if (filtro.empty())
  			filtro = format("(92->LUOGODON == \"%s\")",(const char*)_punto);
			else
			{
				filtro << " && ";
				filtro << format("(92->LUOGODON == \"%s\")",(const char*)_punto);
			}				
		}
		_cur->setfilter((const char*) filtro, TRUE);
		TString16 codsez, codsot, punto, tipodon;
		int anno, mese, giorno;
		TDate data;
		long numero;  
		bool primadon;
		TRectype& recdon = _cur->curr();
		TRectype& recsog = _cur->curr(LF_SOGGETTI);
  	long last = _cur->items();   
  	TProgind prg (last, "Elaborazione in corso... Prego attendere", FALSE, TRUE, 30);
  	for ( *_cur=0; _cur->pos() < last; ++(*_cur) )
  	{
    	prg.addstatus(1);
    	punto = recdon.get(DON_LUOGODON);
			codsez = recdon.get(DON_CODSEZ);
			codsot = recdon.get(DON_CODSOT);
			if (codsez.empty())
			{
				codsez = recsog.get(SOG_CODSEZ);
				codsot = recsog.get(SOG_CODSOT);
			}
			data = recdon.get_date(DON_DATADON);
			anno = data.year();
			mese = data.month();
			giorno = data.day();
			tipodon = recdon.get(DON_TIPODON);
			primadon = recdon.get_bool(DON_PRIMADON);
			stat.zero();
			if (_suddivisa == 'S')
			{
				stat.put(ATS_CODSEZ, codsez);  	 
				stat.put(ATS_CODSOT, codsot);  	 
			}
			else
				stat.put(ATS_PUNTO, punto);  	 								
			//stat.put(ATS_DATA, data);  	 
			stat.put(ATS_ANNO, anno);
			stat.put(ATS_MESE, mese);
			stat.put(ATS_GIORNO, giorno);						
			stat.put(ATS_TIPODON, tipodon);  	 
			if (stat.read() == NOERR)
			{
				numero = stat.get_long(ATS_NUMERO);
				numero++;
				stat.put(ATS_NUMERO, numero);
				if (_primedon && primadon)
				{
					numero = stat.get_long(ATS_NUMPRIME);
					numero++;
					stat.put(ATS_NUMPRIME, numero);
				}
				int err = stat.rewrite();			
			}			
			else
			{
				stat.zero();
				if (_suddivisa == 'S')
				{
					stat.put(ATS_CODSEZ, codsez);  	 
					stat.put(ATS_CODSOT, codsot);  	 
				}
				else
					stat.put(ATS_PUNTO, punto);  	 								
				stat.put(ATS_ANNO, anno);    
				stat.put(ATS_MESE, mese);
				stat.put(ATS_GIORNO, giorno);						
				stat.put(ATS_DATA, data);  	 
				stat.put(ATS_TIPODON, tipodon);  	 
				numero = 1;
				stat.put(ATS_NUMERO, numero);
				if (_primedon && primadon)
					stat.put(ATS_NUMPRIME, numero);
				int err = stat.write();
			}
		}	
		return (stat.eod() > 0);
	}		
	else
		return FALSE;	
}         

int at3500(int argc, char* argv[])
{
	TRiepilogoGiornaliero a;
	a.run(argc, argv, "Riepilogo giornaliero donazioni");
	return 0;
}