#include <applicat.h>
#include <automask.h>
#include <progind.h>
#include <reprint.h>
#include <reputils.h>

#include "../db/dblib.h"
#include "../ve/velib.h"

#include "ps0920.h"
#include "ps0920300a.h"

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

public:
  TPianifica_impianti_mask();
  virtual ~TPianifica_impianti_mask();
};

TPianifica_impianti_mask::TPianifica_impianti_mask()
            : TAutomask("ps0920300a")
{
}

TPianifica_impianti_mask::~TPianifica_impianti_mask()
{  
}             

bool TPianifica_impianti_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
	const int id = o.dlg();
	switch (id)
	{
		case F_ADATA:
			if (e == fe_modify)
			{
				const TDate dadata = get_date(F_DADATA);
				const int daanno = dadata.year();
				const TDate adata = o.get();
				const int aanno = adata.year();
				if (daanno != aanno)
					return error_box(TR("Le date devono appartenere allo stesso anno!"));
			}
			break;
		default:
			break;
	}
  return true;
}


/////////////////////////////////////////////////////////////////
//	APPLICAZIONE
/////////////////////////////////////////////////////////////////
class TPianifica_impianti : public TSkeleton_application  
{
  TPianifica_impianti_mask * _mask;
	virtual bool check_autorization() const {return false;}
  virtual const char * extra_modules() const {return "ve";}
	bool find_my_sister_row(const TRiga_documento& source_row, const TString& a_codnum, const TCodice_articolo& son_codartmag, 
													const TString& a_impianto, TRectype& sister_row, TLog_report& log) const;
	void delete_old_docs();
	void create_new_docs(TLog_report& log);

protected:
  virtual void main_loop();
  virtual bool create();

public:
  const TPianifica_impianti_mask & mask() const {return *_mask;}
  virtual ~TPianifica_impianti();
};


void TPianifica_impianti::delete_old_docs()
{
  TDate dadata = _mask->get_date(F_DADATA);
	TDate adata = _mask->get_date(F_ADATA);
	const int lastday = adata - dadata;
	const int anno = dadata.year();
  const TString& codnum = _mask->get(F_ANUM);	//accoppa i documenti con numerazione di destinazione..
	const TString& impianto = _mask->get(F_DAIMP);	//..e con l'impianto sorgente! (rompe la supersimmetria)

  TRelation rel_doc(LF_DOC);

  TRectype darec(LF_DOC), arec(LF_DOC);
	TDate from(1, 1, anno - 1);
	TDate to(31, 12, anno);

	darec.put(DOC_DATADOC, from);
  darec.put(DOC_PROVV, "D");
  darec.put(DOC_ANNO, anno);
  darec.put(DOC_CODNUM, codnum);

	arec.put(DOC_DATADOC, to);
  arec.put(DOC_PROVV, "D");
  arec.put(DOC_ANNO, anno);
  arec.put(DOC_CODNUM, codnum);

	TString filtro;
	filtro << "CODNUM='" << codnum << "'";

  TCursor cur_doc (&rel_doc, filtro, 3, &darec, &arec);
  const long items = cur_doc.items();
  cur_doc.freeze();
  TProgind progind(items, "Eliminazione vecchi documenti in corso...", false, true);

  dadata += _delays[0];
  adata += _delays[lastday ];
	for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc)
  { 
    progind.addstatus(1);
    TDocumento doc(cur_doc.curr());
		//trovato un documento che soddisfa il darec/arec deve eliminarlo se la prima riga ha impianto..
		//..uguale a quello nel campo F_AIMP sulla maschera
		const TDate h_datacons = doc.get_date(DOC_DATACONS);
  	bool imp_ok =false, datacons_ok = false;

		for (int i = 1; i <= doc.physical_rows(); i++)
		{
			const TRiga_documento& rigadoc = doc[i];
			if (rigadoc.get(RDOC_IMPIANTO) == impianto)
				imp_ok = true;
			const TDate datacons = rigadoc.get_date(RDOC_DATACONS);
			if (datacons.ok())
				datacons_ok = (datacons >= dadata) && (datacons <= adata);
			else
				datacons_ok = (h_datacons >= dadata) && (h_datacons <= adata);
			if (imp_ok && datacons_ok)
			{
				doc.remove();
				break;
			}
		} //for(int i =...
  }	//for(cur_doc..
}

bool TPianifica_impianti::find_my_sister_row(const TRiga_documento& source_row, const TString& a_codnum, 
																						 const TCodice_articolo& son_codartmag,
																						 const TString& a_impianto, TRectype& sister_row,
																						 TLog_report& log) const
{
	TRelation rel_righedoc(LF_RIGHEDOC);
	TString filtro;
	filtro << "(CODNUM='" << a_codnum << "')&&";
	filtro << "(IMPIANTO='" << a_impianto << "')&&";
	filtro << "(CODARTMAG='" << son_codartmag << "')";
	TCursor cur_righedoc(&rel_righedoc, filtro, 4, &source_row, &source_row);
	const long items = cur_righedoc.items();
	
	if (items != 1)
	{
		TString errore;
		if (items == 0)
		{
			errore.format("Non ci sono documenti per l'articolo %s", (const char*)son_codartmag);
			log.log(2, errore);
		}
		else
		{
			errore.format("Ci sono %ld documenti per l'articolo %s", items, (const char*)son_codartmag);
			log.log(1, errore);
		}
	}

	if (items > 0)
	{
		cur_righedoc = 0;
		sister_row = cur_righedoc.curr();
	}
	return items > 0;
}

void TPianifica_impianti::create_new_docs(TLog_report& log)
{
	const TDate dadata = _mask->get_date(F_DADATA);
	const TDate adata = _mask->get_date(F_ADATA);
	const int anno = dadata.year();
  const TString& da_codnum = _mask->get(F_DANUM);	//crea documenti con numerazioni sorgenti...
	const TString& da_impianto = _mask->get(F_DAIMP);	//..con l'impianto sorgente! (conserva la supersimmetria)

	//questi servono dopo!!!
	const TString& a_codnum = _mask->get(F_ANUM);
	const int ritardo = _mask->get_int(F_RITARDO);
	const TString& a_impianto = _mask->get(F_AIMP);

  TRelation rel_doc(LF_DOC);

  TRectype darec(LF_DOC), arec(LF_DOC);
	TLocalisamfile db(LF_RDIST);
	TDate from(1, 1, anno - 1);
	TDate to(31, 12, anno);
	
	db.setkey(2);
	darec.put(DOC_DATADOC, from);	
	
  darec.put(DOC_PROVV, "D");
  darec.put(DOC_ANNO, anno);
  darec.put(DOC_CODNUM, da_codnum);

	arec.put(DOC_DATADOC, to);
  arec.put(DOC_PROVV, "D");
  arec.put(DOC_ANNO, anno);
  arec.put(DOC_CODNUM, da_codnum);

	TString filtro;
	filtro << "CODNUM='" << da_codnum << "'";
  TCursor cur_doc (&rel_doc, filtro, 3, &darec, &arec);
  const long items = cur_doc.items();
  cur_doc.freeze();
  TProgind progind(items, "Generazione nuovi documenti in corso...", false, true);

	TDistinta_tree albero;
	TRectype sister_row(LF_RIGHEDOC);

  for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc)
  { 
    progind.addstatus(1);
    TDocumento doc(cur_doc.curr());
		TDocumento nuovo_doc('D', anno, codnum, 0);

		// crea un documento...
		nuovo_doc.copy_data(nuovo_doc, doc);
		nuovo_doc.put(DOC_TIPODOC, codnum);	//il tipo deve corrispondere alla numerazione!
		nuovo_doc.put(DOC_STATO, 2);
		TDate datadoc = nuovo_doc.get(DOC_DATADOC);

		TDate h_datacons = nuovo_doc.get(DOC_DATACONS);

		if (h_datacons < dadata || h_datacons > adata)
			continue;

    TDate datacons = h_datacons;

		
		const int ndays = datacons - dadata;
	
		if (ndays > 365)
			continue;

		datacons += _delays[ndays];
		nuovo_doc.put(DOC_DATACONS, datacons);
		
		for (int i = 1; i <= doc.rows(); i++)
		{
			const TRiga_documento& source_row = doc[i];	//riga del documento sorgente
			const TString80 codice(source_row.get(RDOC_CODARTMAG));

			if (codice == "008BTN008033MP01")
				int  i = 1;

  		//il casino va fatto solo se la riga non e' gia' evasa, l'impianto e' quello selezionato e la riga e' riga articolo
			if (source_row.get(RDOC_IMPIANTO) == da_impianto && source_row.is_articolo())
			{

				db.zero();
				db.put("CODCOMP", codice);
				const int err = db.read(_isgteq);

				if (err == NOERR && codice == db.get("CODCOMP"))
				{
					TCodice_articolo son_codartmag;
					albero.curr_code(son_codartmag);	//e' risalito al codice dell'articolo figlio
					//cerca la riga sua sorella, ovvero quella che viene dalla stessa riga ordine mamma originaria
					if (find_my_sister_row(source_row, a_codnum, son_codartmag, a_impianto, sister_row, log))
					{
						TDate datacons = sister_row.get_date(RDOC_DATACONS);
						//ignora righe con data consegna fuori dal range selezionato
						if (datacons < dadata || datacons > adata)
							continue;
						datacons += ritardo;
						const int priority = sister_row.get_int(RDOC_PRIORITY);

						//crea un documento...
						TDocumento nuovo_doc('D', anno, a_codnum, 0);
						nuovo_doc.copy_data(nuovo_doc, doc);
						nuovo_doc.put(DOC_TIPODOC, a_codnum);	//il tipo deve corrispondere alla numerazione!
						
						//..e la sua riga vuota
						TRiga_documento& nuova_rigadoc = nuovo_doc.new_row(source_row.get(RDOC_TIPORIGA));
						//riempie la nuova riga 
						nuovo_doc.copy_data(nuova_rigadoc, source_row);
						nuova_rigadoc.put(RDOC_PRIORITY, priority);
						nuova_rigadoc.put(RDOC_DATACONS, datacons);
						
						//..e alla fine scrive testata e riga!!
						int err = nuovo_doc.write();
						if (err != NOERR)
						{
							TString errore;
							errore.format("Errore %d nella scrittura del documento %ld", err, nuovo_doc.get_long(DOC_NDOC));
							log.log(2, errore);
						}
							if (!datacons.ok())
								datacons = h_datacons;
							const int ndays = datacons - dadata;
							datacons += _delays[ndays];
							if (datacons < dadata || datacons > adata)
								continue;
							//..e la sua riga vuota
							TRiga_documento& nuova_rigadoc = nuovo_doc.new_row(source_row.get(RDOC_TIPORIGA));
							//riempie la nuova riga 

							nuovo_doc.copy_data(nuova_rigadoc, source_row);
							nuova_rigadoc.put(RDOC_CODART, dest_codart);
							nuova_rigadoc.put(RDOC_CODARTMAG, dest_codart);
							nuova_rigadoc.put(RDOC_PRIORITY, priority);
							nuova_rigadoc.zero(nuova_rigadoc.field_qtaevasa());
							nuova_rigadoc.zero(RDOC_RIGAEVASA);
							datacons = source_row.get_date(RDOC_DATACONS);
							if (datacons.ok())
							{
								datacons += _delays[ndays];
								nuova_rigadoc.put(RDOC_DATACONS, datacons);
							}
							nuova_rigadoc.put(RDOC_IMPIANTO, a_impianto);
							const TString &linea = lav->cod_linea(0);
							nuova_rigadoc.put(RDOC_LINEA, linea);
							found = true;
						}

					}
				}
			}	//if(source_row.get...
		}	//for(int i...
	}	//for(cur_doc...
}

void TPianifica_impianti::main_loop()
{
  while (_mask->run() == K_ENTER)
  {
	  TDate dadata = _mask->get_date(F_DADATA);
		TDate adata = _mask->get_date(F_ADATA);
		TDate data;
		int ndays = adata - dadata + 1;
		const int ritardo = _mask->get_int(F_RITARDO);
		_delays[0] = ritardo;

		for (int i = 1; i < 366; i++)
		{
			data = dadata;
			data += i;
			const TDate workdate = data;
			if (!data.is_holiday() && data.wday() != 6)
			{
				TDate end_date = data;
				end_date += _delays[i - 1];
				while (end_date.is_holiday() || end_date.wday() == 6)
					++end_date;
				_delays[i] = end_date - workdate;
			}
			else 
				_delays[i] = _delays [i - 1];
		}
		delete_old_docs(); //intanto accoppa i vecchi documenti di tipo destinazione
		//poi crea i nuovi documenti di produzione
		TLog_report log("Errori generazione documenti pianificazione");

		create_new_docs(log);	

		TReport_book buc;
		buc.add(log);
		buc.preview();
	}

bool TPianifica_impianti::create()
{
	open_files(LF_TAB, LF_TABCOM, LF_DOC, LF_RIGHEDOC, LF_DIST, LF_RDIST, LF_ANAMAG, NULL);
	_mask = new TPianifica_impianti_mask;
	return TSkeleton_application:: create();
}

TPianifica_impianti::~TPianifica_impianti()
{
	delete _mask;
}

TPianifica_impianti & app() { return (TPianifica_impianti&) main_app();}

int ps0920300(int argc, char* argv[])
{
  TPianifica_impianti a;
  a.run(argc, argv, "Pianificazione impianti");
  return 0;
}