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

#include "at9.h"

// nomi campi maschera
#include "at9100a.h"
          
// nomi dei campi
#include "soggetti.h"
#include "contsan.h"
#include "atstats.h"
#include "sezioni.h"

#define ALIAS_TCS 200

// classe per la definizione di una riga di statistica
class TRigaSSosp : public TObject
{                             
	TString16			_tiposos;
	TArray				_valori;

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

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

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

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

void TRigaSSosp::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 TRigaSSosp::azzera_valori()
{
	_valori.destroy();
}
                   
class TStatSogSosp : public TApplication
{
	TMask*					_msk;
	TRelation*   		_rel;
	TCursor*				_cur;
	TLocalisamfile* _sezioni;
	TLocalisamfile* _soggetti;
	TLocalisamfile* _contsan;
	TLocalisamfile* _atstats;
	TAssoc_array*		_colonne;
	TAssoc_array*		_sospensioni;
	TArray					_righe;
	TString16				_sezini, _sotini, _sezfin, _sotfin;
	TDate						_dataini, _datafin;
	bool 						_solotot;
	int							_sezionistampate;

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 TString16 tiposos);
	bool riepilogo();
	bool stampa(); 
	bool crea_colonne();
	bool crea_righe();
	void azzera_righe();
	void stampa_sezione(TString16 codsez, TString16 codsot);
	void crea_intestazione();
public:
	TStatSogSosp() {}
	
};

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

int TStatSogSosp::data2row(const TString16 tiposos)
{       
	real& indicer = (real&)_sospensioni->find((const char*) tiposos);
	return ((int) indicer.integer());
}

bool TStatSogSosp::crea_righe()
{                     
	TTable tcs("TCS");
	TString16 tiposos = "**";
	int indice = 0;
	_sospensioni->destroy();
	real* oggetto1 = new real(indice);
	_sospensioni->add((const char*) tiposos, (TObject*) oggetto1);
	_righe.add(new TRigaSSosp(tiposos), indice);
	for (tcs.first(); !tcs.eof(); tcs.next())
	{          
		if (tcs.get("S6")[0] == 'S')
		{
			indice++;
			tiposos = tcs.get("CODTAB");
			_righe.add(new TRigaSSosp(tiposos), indice);
			real* oggetto = new real(indice);
			_sospensioni->add((const char*) tiposos,(TObject*) oggetto);
		}	
	}		
	return _righe.items()>0;	
}

bool TStatSogSosp::crea_colonne()
{                   
	_colonne->destroy();
	real contatore(ZERO);
	real* oggetto = new real(contatore);                                
	const char* indice = "N"; // numero soggetti sospesi
	_colonne->add(indice,(TObject*)oggetto);
	indice = "D"; // durata
	contatore = contatore+1;
	real* oggetto2 = new real(contatore);                                	
	_colonne->add(indice,(TObject*)oggetto2);
	return true;
}

bool TStatSogSosp::create()
{
	TApplication::create();
	_msk = new TMask("at9100a");
	_rel = new TRelation(LF_CONTSAN);
  _rel->add(LF_SOGGETTI, "CODICE==CODICE");
  //_rel->add("TCS", "CODTAB==TIPOCON",1,0,ALIAS_TCS);
  _rel->add("TCS", "CODTAB==TIPOCON");
  _contsan  = new TLocalisamfile(LF_CONTSAN);
  _soggetti = new TLocalisamfile(LF_SOGGETTI);
	_atstats = new TLocalisamfile(LF_ATSTATS);
	_sezioni = new TLocalisamfile(LF_SEZIONI);
	_colonne = new TAssoc_array();
	_sospensioni = new TAssoc_array();
  dispatch_e_menu(BAR_ITEM_ID(1));
	return true;
}	

bool TStatSogSosp::destroy()	
{ 
	delete _sospensioni;
	delete _colonne;
	delete _sezioni;
	delete _atstats;   
	delete _soggetti;
	delete _contsan;
	delete _rel;
	delete _msk;
	return TApplication::destroy();
}

bool TStatSogSosp::menu(MENU_TAG m)
{ 
	TMask& msk = get_mask();
	KEY tasto;
 	tasto = msk.run();
 	if (tasto == K_ENTER)
 	{
 		_sezini  = _msk->get(F_SEZINI);
 		_sotini  = _msk->get(F_SOTINI);
 		_sezfin  = _msk->get(F_SEZFIN);
 		_sotfin  = _msk->get(F_SOTFIN);
 		_dataini = _msk->get_date(F_DATAINI);
 		_datafin = _msk->get_date(F_DATAFIN);
 		_solotot = _msk->get_bool(F_SOLOTOT);
		if (riepilogo())
			stampa();
 	}
 	return false;
}  

void TStatSogSosp::crea_intestazione()
{ 
	TPrintrow row;
	TString256 sep;
	sep = "STATISTICA SOGGETTI SOGGETTI SOSPESI";
	sep << " dal " << _dataini.string() << " al " << _datafin.string();
	sep.center_just(80);
	row.put(sep);
  row.put("@>", 1);
  row.put("Pag. @#", 72);
  printer().setheaderline(2, row);
  sep = "";     
  sep.center_just(80);
  row.reset();
  row.put(sep);
  printer().setheaderline(3, row);	  
  sep = "";
  sep << "Tipo sospensione       Numero sospesi         Durata";
  row.reset();
  row.put(sep);
	printer().setheaderline(5, row);  
	sep = "";
	sep.fill('-',80);
	row.reset();
	row.put(sep);
	printer().setheaderline(6, row);
}

bool TStatSogSosp::stampa()
{ 
	if (printer().open())
	{
		_sezionistampate = 0;
		crea_intestazione();
		TRelation* relstat = new TRelation(LF_ATSTATS);
		TCursor* curstat = new TCursor(relstat, "", 1);
		TString16 oldsez = "**";
		TString16 oldsot = "**";
		long numero, numero2;
		TString16 actsez, actsot, tiposos;
		long last = curstat->items();
	  for ( *curstat=0; curstat->pos() < last; ++(*curstat) )
	  {
			actsez = curstat->curr().get(ATSS_CODSEZ);																						  	
			actsot = curstat->curr().get(ATSS_CODSOT);		
			tiposos = curstat->curr().get_int(ATSS_CATDON);		
			numero = curstat->curr().get_int(ATSS_NUMERO);		
			numero2 = curstat->curr().get_int(ATSS_NUMERO2);		
			if (actsez != oldsez || actsot != oldsot)
			{                 
				if (oldsez != "**" && oldsot != "**")
				{
					stampa_sezione(oldsez,oldsot);
					azzera_righe();
				}
				oldsez = actsez;
				oldsot = actsot;
			}				
			TRigaSSosp& riga = (TRigaSSosp&)_righe[data2row(tiposos)];
			const char* indicen = "N";
			real& colonnan = (real&)_colonne->find(indicen);
			real n = numero;
			riga.aggiorna_valore((int) colonnan.integer(),n);
			const char* indiced = "D";
			real& colonnad = (real&)_colonne->find(indiced);
			n = numero2;
			riga.aggiorna_valore((int) colonnad.integer(),n);
		}                             
		if (oldsez != "**" && oldsot != "**")
			stampa_sezione(oldsez,oldsot);
		delete curstat;
		delete relstat;
		printer().close();
		return true;
	}
	else
		return FALSE;		
}

void TStatSogSosp::azzera_righe()
{   
	TString16 tiposos = "**";
	int indice = data2row(tiposos);
	TRigaSSosp& riga = (TRigaSSosp&)_righe[indice];
	riga.azzera_valori();
	TTable tcs("TCS");
	for (tcs.first(); !tcs.eof(); tcs.next())
	{ 
		tiposos = tcs.get("CODTAB");
		if (tcs.get("S6")[0] == 'S')
		{
			indice = data2row(tiposos);
			TRigaSSosp& riga = (TRigaSSosp&)_righe[indice];
			riga.azzera_valori();
		}	
	}		
}

void TStatSogSosp::stampa_sezione(TString16 codsez, TString16 codsot)
{ 
	TPrintrow row;
	TString256 rigastampa;
	if (codsez == "ZZ" && codsot == "ZZ")
	{
		if (_sezionistampate != 1)
		{
			//rigastampa = "RIEPILOGO TOTALE PER TUTTE LE SEZIONI STAMPATE";
			rigastampa = "";
			rigastampa << "RIEPILOGO TOTALE SEZIONI DA " << _sezini << '/' << _sotini << " A " << _sezfin << '/' << _sotfin;
		}	
	}	
	else
	{
		_sezionistampate++;
		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;
			}
		}
	}	
	if ((codsez == "ZZ" && codsot == "ZZ" && _sezionistampate != 1) || (codsez != "ZZ"))
	{
		rigastampa.center_just(80);
		row.put(rigastampa);
	  printer().setheaderline(1, row);
	  
	  TRigaSSosp rigatotali("  ");
		TString16 valore;
		TString16 catdon;
	
		TTable tcs("TCS");
		for (tcs.first(); !tcs.eof(); tcs.next())
		{ 
			TString16 tiposos = tcs.get("CODTAB");
			TRigaSSosp& riga = (TRigaSSosp&)_righe[data2row(tiposos)];
			row.reset();
			rigastampa = "";
			rigastampa << tiposos;
			rigastampa << " ";
			rigastampa << tcs.get("S0");
			int pos = 41;
			const char* indicen = "N";
			real& colonnan = (real&)_colonne->find(indicen);
			rigatotali.aggiorna_valore((int) colonnan.integer(),riga[(int) colonnan.integer()]);
			valore = "";
			valore.format("%8d",riga[(int) colonnan.integer()].integer());
			rigastampa.overwrite((const char*)valore, pos);
			pos = pos+8;
			const char* indiced = "D";
			real& colonnad = (real&)_colonne->find(indiced);
			rigatotali.aggiorna_valore((int) colonnad.integer(),riga[(int) colonnad.integer()]);
			valore = "";
			valore.format("%8d",riga[(int) colonnad.integer()].integer());
			rigastampa.overwrite((const char*)valore, pos);
			pos = pos+8;
			row.put((const char*) rigastampa);
			printer().print(row);			
		}	
			
		// stampa totali per sezione
		rigastampa = "";
		rigastampa.fill('-',80);
		row.reset();
		row.put(rigastampa);
		printer().print(row);
		row.reset();
		rigastampa = "";
		rigastampa = "Totale";
		int pos = 41;
		const char* indicen = "N";
		real& colonnan = (real&)_colonne->find(indicen);
		valore = "";
		valore.format("%8d",rigatotali[(int) colonnan.integer()].integer());
		rigastampa.overwrite((const char*)valore, pos);
		pos = pos+8;
		const char* indiced = "D";
		real& colonnad = (real&)_colonne->find(indiced);
		valore = "";
		valore.format("%8d",rigatotali[(int) colonnad.integer()].integer());
		rigastampa.overwrite((const char*)valore, pos);
		pos = pos+8;
		row.put((const char*) rigastampa);
		printer().print(row);			
		printer().formfeed();
	}		
}

bool TStatSogSosp::riepilogo()
{            
	if (crea_colonne() && crea_righe())
	{   
		// cancello i risultati della elaborazione precedente
		TLocalisamfile stat(LF_ATSTATS);
		for (stat.first(); !stat.eof(); stat.next())
			stat.remove();
		stat.setkey(1);			
	  TRectype da(LF_CONTSAN);
  	TRectype a (LF_CONTSAN);
  	if (_dataini.ok())
			da.put(CON_DATACON, _dataini);
  	if (_datafin.ok())
			a.put(CON_DATACON, _datafin);
	  _cur = new TSorted_cursor(_rel, "94->CODICE|94->DATACON", "", 2, &da, &a);
		TString256 filtro = "";
		// filtro per sezione/sottogruppo
	 	if (_sezini.not_empty())
	 	{
	 		if (_sotini.not_empty())
	 		{                    
	 			filtro << "(";
	 			filtro << format("(90->CODSEZ > \"%s\")",(const char*)_sezini);
	 			filtro << " || ";
	 			filtro << "(" << format("(90->CODSEZ == \"%s\")",(const char*)_sezini);
	 			filtro << " && ";
	 			filtro << format("(90->CODSOT >= \"%s\")",(const char*)_sotini);
	 			filtro << ")";
	 			filtro << ")";
	 		}
	 		else
		 			filtro << format("(90->CODSEZ >= \"%s\")",(const char*)_sezini);
	 	}
	 	if (_sezfin.not_empty())
	 	{
 			if (filtro.not_empty())
 				filtro << " && "; 
	 	
	 		if (_sotfin.not_empty())
	 		{          
	 			filtro << "(";
	 			filtro << format("(90->CODSEZ < \"%s\")",(const char*)_sezfin);
	 			filtro << " || ";
	 			filtro << "(" << format("(90->CODSEZ == \"%s\")",(const char*)_sezfin);
	 			filtro << " && ";
	 			filtro << format("(90->CODSOT <= \"%s\")",(const char*)_sotfin);
	 			filtro << ")";
	 			filtro << ")";
	 		}
	 		else
	 			filtro << format("(90->CODSEZ <= \"%s\")",(const char*)_sezfin);
		}
		if (filtro.not_empty())
			filtro << " && ";
		//filtro << "((TCS->S6 == \"S\") || (TCS->S6 == \"B\"))";     
		filtro << "(TCS->S6 == \"S\")";     
	  _cur->setfilter((const char*) filtro, true);
	  long numero, numero2; // numero sospesi, durata
		TString16 codsez, codsot, tiposos;
		TDate dataini, datafin;
		TRectype& recsog = _cur->curr(LF_SOGGETTI);
		TRectype& reccon = _cur->curr();
		bool ok=FALSE;
		long codice = 0;
		long durata = 0;
  	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);
    	if (codice == reccon.get_long(CON_CODICE))
    	{                
    		ok = FALSE;
				dataini = reccon.get_date(CON_DATACON);
				datafin = reccon.get_date(CON_PROSSDATA);
				if (datafin.ok())    	
    			durata = durata + (datafin-dataini);
    	}	
    	else
    	{
    		if (codice != 0)
    			ok = true;
    		codice = reccon.get_long(CON_CODICE);
				tiposos = reccon.get(CON_TIPOCON);
			}
			if (ok)
			{	
				if (!_solotot)
				{
					codsez = recsog.get(SOG_CODSEZ);
					codsot = recsog.get(SOG_CODSOT);
					stat.zero();
					stat.put(ATSS_CODSEZ, codsez);  	 
					stat.put(ATSS_CODSOT, codsot);  	 
					stat.put(ATSS_CATDON, tiposos);
					if (stat.read() == NOERR)
					{
						numero = stat.get_long(ATSS_NUMERO);
						numero++;
						stat.put(ATSS_NUMERO, numero);
						numero2 = stat.get_long(ATSS_NUMERO2);
						numero2 = numero2+durata;
						stat.put(ATSS_NUMERO2, numero2);
						stat.rewrite();			
					}			
					else
					{
						stat.put(ATSS_CODSEZ, codsez);  	 
						stat.put(ATSS_CODSOT, codsot);  	 
						stat.put(ATSS_CATDON, tiposos);
						numero = 1;
						numero2 = durata;
						stat.put(ATSS_NUMERO, numero);
						stat.put(ATSS_NUMERO2, numero2);
						stat.write();
					}
				}	
				stat.zero();
				stat.put(ATSS_CODSEZ, "ZZ");  	 
				stat.put(ATSS_CODSOT, "ZZ");  	 
				stat.put(ATSS_CATDON, tiposos);
				if (stat.read() == NOERR)
				{
					numero = stat.get_long(ATSS_NUMERO);
					numero++;
					stat.put(ATSS_NUMERO, numero);
					numero2 = stat.get_long(ATSS_NUMERO2);
					numero2 = numero2+durata;
					stat.put(ATSS_NUMERO2, numero2);
					stat.rewrite();			
				}			
				else
				{
					stat.put(ATSS_CODSEZ, "ZZ");  	 
					stat.put(ATSS_CODSOT, "ZZ");  	 
					stat.put(ATSS_CATDON, tiposos);
					numero = 1;
					numero2 = durata;
					stat.put(ATSS_NUMERO, numero);
					stat.put(ATSS_NUMERO2, numero2);
					stat.write();
				}
			}				
		}	
		return (stat.eod() > 0);
	}		
	else
		return FALSE;	
}         

int at9100(int argc, char* argv[])
{
	TStatSogSosp a;
	a.run(argc, argv, "Statistica soggetti sospesi");
	return 0;
}