#include <applicat.h>
#include <assoc.h>
#include <automask.h>
#include <currency.h>
#include <filetext.h>
#include <msksheet.h>
#include <printer.h>
#include <recarray.h>
#include <relation.h>
#include <sort.h>
   
#include "..\ve\velib.h"

#include "ps0544.h"
#include "ps0544200a.h"
 
class TServus_file: public TFile_text
{
protected:
  virtual void validate(TCursor& cur,TRecord_text& rec, TToken_string& val, TString& str);

public:
  TServus_file(const TString& file_name, const TString& config_name);
  virtual ~TServus_file() { }
};

TServus_file::TServus_file(const TString& file_name, const TString& config_name)
          : TFile_text(file_name, config_name)
{
}

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

  TServus_mask();
  
  virtual ~TServus_mask(){};
};
  
TServus_mask::TServus_mask() :TAutomask ("ps0544200a")
{
}  
  
bool TServus_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  return true;
}

class TServus : public TSkeleton_application
{                     
	TCursor*				   _cur;
  TServus_mask*	 		 _msk;
  TDate							 _dataini, _datafin;
  TServus_file* 		 _trasfile;
  TConfig*					 _configfile;
  long							 _nrecords;
	int								 _cont11, _cont12, _cont13;
	TRiga_documento*	 _riga_doc_curr;
	real							 _tot_mate, _tot_temp, _tot_mano, _tot_vari, _perc ;

virtual const char * extra_modules() const {return "ve";}
  
protected:
  virtual bool create(void);
  virtual bool destroy(void);
  virtual void main_loop() ;
  void azzera_totali() ;
	void aggiorna_totali(const real& materiale, const real& tempi, const real& manodopera, const real& vari);
  void elabora_documenti();
	
  static int calcola_tipo(const TRiga_documento& r);
	static int righe_sort(const TObject** o1, const TObject** o2);

public:   
	const long nrecords() { return _nrecords;};
	const int nriga11() { return _cont11;};
	const int nriga12() { return _cont12;};
	const int nriga13() { return _cont13;};
	const real& tot_temp() { return _tot_temp;};
	const real& tot_mano() { return _tot_mano;};
	const real& tot_vari() { return _tot_vari;};
	const real& tot_mate() { return _tot_mate;};
	const real& perc(const real& perc = -1);
	const TRiga_documento& riga_doc_curr() { return *_riga_doc_curr;};
	TConfig configfile() {return *_configfile;};
  TServus() {} ;
  virtual ~TServus() {} ;
};  

// restituisce un riferimento all' applicazione
inline TServus& app() { return (TServus&) main_app();}

// gestione dei messaggi estesi nei campi
void TServus_file::validate(TCursor& cur,TRecord_text &rec, TToken_string &s, TString& str)
{
  const TString code(s.get(0));
  TString valore;
  if (code == "_FISSO")
  {
    // gestione dei campi fissi per i record delle riba
    // sintassi: _FISSO,!<valore>
    // dove: <valore> � la stringa fissa da emettere
    TString in(s.get());
    CHECK(in[0]=='!',"Macro _FISSO senza carattere '!'");
    in.ltrim(1);
    in.trim();
    valore = in;
  }
  else if (code == "_TELEFONO")
  {
 		valore = cur.curr(LF_CLIFO).get("PTEL");
 		valore << " ";
 		valore << cur.curr(LF_CLIFO).get("TEL");
  }
  else if (code == "_VIRTUALE")
  {
 		TString in(s.get()); 	
 		valore = cur.curr().get(in);
  }
  else if (code == "_IMPORTO")
  {
 		valore = str;
		valore.strip(".");
  }
  else if (code == "_DARIGA")
  {
		valore = "";
 		TString in(s.get());
		if (in == "IMPORTO")
		{
			real importo = app().riga_doc_curr().importo(true, false);
			real perc = app().perc();
			if (perc > 0)
				importo = importo*perc/100;
			valore = importo.string(0,2,'0');
			valore.strip(".");
		}
		else if (in == "PREZZO")
		{
			real importo = app().riga_doc_curr().prezzo(false, false);
			valore = importo.string(0,2,'0');
			valore.strip(".");
		}
		else if (in == "SCONTO")
		{
			TString80 sconto = app().riga_doc_curr().get(RDOC_SCONTO);
			real rs(sconto);
			valore = rs.string(0,1,'0');
			valore.strip(".");
		}
		else if (in == "QTA")
		{
			real qta = app().riga_doc_curr().quantita();
			valore = qta.string(4,1,'0');
			valore.strip(".");
		}
		else
		{
			real qta = app().riga_doc_curr().get_real(RDOC_QTAGG1);
			valore = qta.string(0,2);
			valore.strip(".");
		}
  }
  else if (code == "_ANNO")
  {
 		TString in(s.get()); 	
 		TDate data = cur.curr().get(in);
 		in = data.string();
 		valore = in.mid(8,2);
  }
  else if (code == "_MESE")
  {
 		TString in(s.get()); 	
 		TDate data = cur.curr().get(in);
 		in = data.string();
 		valore = in.mid(3,2);
  }
  else if (code == "_GIORNO")
  {
 		TString in(s.get()); 	
 		TDate data = cur.curr().get(in);
 		in = data.string();
 		valore = in.mid(0,2);
  }
  else if (code == "_PARAMETRI")
  {
 		TString in(s.get()); 	
 		valore = app().configfile().get(in);
  }
  else if (code == "_OGGI")
  {
    TDate data(TODAY);
  	valore = data.string(brief, '-', full, full, amg_date);
  	valore.strip("-");
  }
  else if (code == "_ADESSO")
  {        
  	char time[128];
  	_strtime(time);
  	valore.format("%s", time);
  	valore.strip(":");
  }
  else if (code == "_NUMEROLAVORO")
  {
		valore = str;
  	valore.strip("-");
  }
  else if (code == "_DATA")
  {
		valore = str;
  	valore.strip("-");
  }
  else if (code == "_NRECORDS")
  {
  	valore.format("%ld", app().nrecords());
  }
  else if (code == "_RIGA")
  {
 		TString in(s.get()); 	
		if (in == "11")
	  	valore.format("%ld", app().nriga11());
		else if (in == "12")
	  	valore.format("%ld", app().nriga12());
		else if (in == "13")
	  	valore.format("%ld", app().nriga13());
  }
  else if (code == "_TOTALE")
  {
		real totale;
 		TString in(s.get());
		if (in == "TEMP")
	  	totale = app().tot_temp();
		else if (in == "MATE")
	  	totale = app().tot_mate();
		else if (in == "MANO")
	  	totale = app().tot_mano();
		else if (in == "VARI")
	  	totale = app().tot_vari();
		else if (in == "SOMM")
			totale = app().tot_mano()+app().tot_mate();
		valore = totale.string(0,2);
		valore.strip(".");
  }
  else if (code == "_UPPERCASE")
	{
		valore = str;
		valore.upper();
	}
  else if (code == "_PERCENTUALE")
	{
		real perc(str);
		valore = perc.string(0,0);
		app().perc(perc);
	}
  else NFCHECK("Macro non definita: %s", (const char *)code);
  
  str = valore;
}

bool TServus::create()
{      
	open_files(LF_DOC, LF_CLIFO, LF_COMUNI, LF_CFVEN, 0);
  _msk = new TServus_mask();
  _trasfile = NULL;
	_configfile = new TConfig("ps0544200a.ini", "TRASFERIMENTO");
  return TSkeleton_application::create();
}

bool TServus::destroy()
{             
	if (_trasfile)  
  	delete _trasfile;
	if (_configfile)  
  	delete _configfile;
  delete _msk;

  return TSkeleton_application::destroy();
}

const real& TServus::perc(const real& perc)
{
	if (perc != -1)
		_perc = perc;
	return _perc;
	
}

void TServus::azzera_totali()
{
	_tot_mate	= ZERO;
	_tot_temp	= ZERO;
	_tot_mano	= ZERO;
	_tot_vari	= ZERO;
}


void TServus::aggiorna_totali(const real& materiale, const real& tempi, const real& manodopera, const real& vari)
{
	_tot_mate = _tot_mate+materiale;
	_tot_temp = _tot_temp+tempi;
	_tot_mano = _tot_mano+manodopera;
	_tot_vari = _tot_vari+vari;
}

void TServus::main_loop()
{
	TFilename filename = _configfile->get("NOMEFILE");
	if (filename.exist())
		remove(filename);
  while (_msk->run()!=K_QUIT)
  {                     
  	_trasfile = new TServus_file(filename, "ps0544200.ini");
  	_trasfile->open(filename,'w');
    _trasfile->force_record_separator(TRUE);
  	
    _dataini = _msk->get_date(F_DATAINI);
    _datafin = _msk->get_date(F_DATAFIN);
		elabora_documenti(); 		
		_trasfile->close();
		delete _trasfile;
		_trasfile = NULL;
	}	
}

int TServus::calcola_tipo(const TRiga_documento& r)
{
	const int tipo_riga = r.get_int(RDOC_TIPORIGA);
	const bool art5 = r.get(RDOC_CODART) != "005";

	if (tipo_riga == 6 && art5)
		return 11;
	if (tipo_riga == 1)
		return 12;
	if (tipo_riga == 6 && !art5)
		return 13;

	return 99;
}

int TServus::righe_sort(const TObject** o1, const TObject** o2)
{
  const TRiga_documento& r1 = *(const TRiga_documento*)*o1;
  const TRiga_documento& r2 = *(const TRiga_documento*)*o2;
	const int t1 = calcola_tipo(r1);
	const int t2 = calcola_tipo(r2);
	return t1 - t2;
}	


void TServus::elabora_documenti()
{                
  TSheet_field& sheet = _msk->sfield(F_SHEETDOC);

  TRelation doc_rel(LF_DOC);
  doc_rel.add(LF_RIGHEDOC, "CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC");
  doc_rel.add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
  doc_rel.add(LF_COMUNI, "COM==COMCF", 1, LF_CLIFO);
  TRectype da(LF_DOC);
  TRectype a(LF_DOC);
  const long items = sheet.items();
  TString filt_expr;
	//filt_expr = "(CONTRS != "") && ";
	
	_nrecords = 0;
  if (items > 0)
  {
	  bool ok = TRUE;
	  TString16 codnum;

	  da.put("DATADOC", _dataini);
	  a.put("DATADOC", _datafin);
	  
	  filt_expr << "(";
	  FOR_EACH_SHEET_ROW(sheet, r, row)
	  {
	    codnum = row->get(0);
	    if (codnum.not_empty())
	    {
	    	filt_expr << "(CODNUM==\"";
	    	filt_expr << codnum << "\")||";
	    }
	  }
	  filt_expr.rtrim(2);  
	  filt_expr << ")";

	  doc_rel.lfile().set_curr(new TDocumento);
	  _cur = new TCursor(&doc_rel,filt_expr,3,&da,&a);
	  const long cur_items = _cur ->items(); // Scorre tutti i documenti che rientrano nell'intervallo selezionato
	  if (cur_items != 0) 
	  {
			TRecord_text rech;
			rech.set_type("OP");
			_trasfile->autoload(rech, *_cur); 
			_trasfile->write(rech);
			for (*_cur = 0; _cur->pos() < cur_items; ++(*_cur))
			{
				TString16 contrs = _cur->curr().get("CONTRS");
				if (contrs.not_empty())
				{
					azzera_totali();				
					TRecord_text rec;
  				rec.set_type("01");
  				_trasfile->autoload(rec, *_cur); 
  				_trasfile->write(rec);
					_nrecords++;
  				rec.set_type("02");
  				_trasfile->autoload(rec, *_cur); 
					_trasfile->write(rec);
  				_nrecords++;
					TDocumento documento = doc_rel.curr();
					documento.body(LF_RIGHEDOC).sort(righe_sort);
					_cont11 = _cont12 = _cont13 = 0;
					for (int i=1;i<=documento.rows();i++)
					{             
						const TRiga_documento& rec_rdoc = documento[i];
						_riga_doc_curr = new TRiga_documento(rec_rdoc);
						const int tipo_record = calcola_tipo(rec_rdoc);
						if (tipo_record >= 11 && tipo_record <= 13)
						{
							doc_rel.curr(LF_RIGHEDOC) = rec_rdoc;

							switch (tipo_record)
							{
							case 11:
								{
									rec.set_type("11");
  								_cont11++;
									//real ore = rec_rdoc.get_real(RDOC_QTA);
								}
								break;
							case 12:
								{
									rec.set_type("12");
  								_cont12++;
									//real importo = rec_rdoc.get_real(RDOC_PREZZO);
								}
								break;
							case 13:
								{
									rec.set_type("13");
  								_cont13++;
									//real importo = rec_rdoc.get_real(RDOC_PREZZO);
								}
								break;
							default:
								break;
							}
  						_trasfile->autoload(rec, *_cur); 
  						_trasfile->write(rec);
							_nrecords++;
							switch (tipo_record)
							{
							case 11:
								{
									real importo = rec_rdoc.importo(true, false);
									real perc = app().perc();
									if (perc > 0)
										importo = importo*perc/100;
									real ore = rec_rdoc.quantita();
									aggiorna_totali(ZERO, ore, importo, ZERO);
								}
								break;
							case 12:
								{
									real importo = rec_rdoc.importo(true, false);
									real perc = app().perc();
									if (perc > 0)
										importo = importo*perc/100;
									aggiorna_totali(importo, ZERO, ZERO, ZERO);
								}
								break;
							case 13:
								{
									real importo = rec_rdoc.importo(true, false);
									aggiorna_totali(ZERO, ZERO, ZERO, importo);
								}
								break;
							default:
								break;
							}
						}
						delete _riga_doc_curr;
					}  
  				rec.set_type("09");
  				_trasfile->autoload(rec, *_cur); 
  				_trasfile->write(rec);
					_nrecords++;
				}
			}
			TRecord_text recf;
			recf.set_type("CL");
			_trasfile->autoload(recf, *_cur); 
			_trasfile->write(recf);
		}                  
	  delete _cur;
	}  
}


int ps0544200(int argc, char **argv) 
{
  TServus a;
  a.run(argc, argv, "Trasferimento a SERVUS");
  return 0;
}