#include <automask.h>
#include <defmask.h>
#include <filetext.h>
#include <printer.h>
#include <progind.h>
#include <relapp.h>
#include <modaut.h>
#include <utility.h>
#include <viswin.h>

#include "../ve/velib04.h"
#include "mr0500a.h"
#include "mr0500b.h"
#include "mr0500c.h"
#include "mrplib.h"

///////////////////////////////////////////////////////////
// TElabora_mask
///////////////////////////////////////////////////////////
class TElabora_mask : public TAutomask
{ 

protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);

public:
  TElabora_mask() : TAutomask("mr0500c") { }
};

bool TElabora_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
	return true;
}

///////////////////////////////////////////////////////////
// TLoadfile_mask
///////////////////////////////////////////////////////////
class TLoadfile_mask : public TAutomask
{ 

protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);

public:
  TLoadfile_mask() : TAutomask("mr0500b") { }
};

bool TLoadfile_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())                                                                      //eventi, tipo pressione dei tasti
  {       
  case F_FILE:
    if(e==fe_button)                   //se e (che � l'evento) = pressione del bottone 'cerca' (fe button)
    {
      DIRECTORY dir; 
      FILE_SPEC fs;
    
      TFilename fname=o.get();         //se il nome del file non esiste -> gli assegna automaticamente il nome
      if(fname == "")                  //articoli.dat
        fname = "articoli";
      
      xvt_fsys_get_dir(&dir);          //funzioni di xvt (grafica); utilizzate per creare la finestra di ricerca del
      xvt_fsys_get_dir(&fs.dir);       //file di tipo .dat (� una finestra tipo gestione risorse Windows)
      strcpy(fs.type, "dat");
      strcpy(fs.name, fname);
      strcpy(fs.creator, "ELD");
        
      const bool good = xvt_dm_post_file_open(&fs, "Selezionare il file ...") == FL_OK;
      xvt_fsys_set_dir(&dir);
                     
      if (good)
      {                 
        xvt_fsys_convert_dir_to_str(&fs.dir, fname.get_buffer(), fname.size());   //converte il nome della directory in una
        fname.add(fs.name);                                                       //stringa aggiungendo il path del file
        o.set(fname);                                                         //mostra il campo sul video (la funzione set) 
      }
      
    }
    if(e==fe_init && o.get().empty())                  
			o.set("prod.dat");
    if(e==fe_close)                //se e = alla pressione del bottone 'chiudi' (fe_close) controlla che il campo sia stato
    {                              //riempito correttamente nella maschera
      TFilename n = o.get();
      return n.exist();
    }     
    break;
		default:
    break;
	}
	return true;
}

///////////////////////////////////////////////////////////
// TRilprod_mask
///////////////////////////////////////////////////////////
typedef enum TTipo_rec { _no_type = 0, _start = 1, _end = 2, _rett = 3};

class TRilprod_mask : public TAutomask
{ 

protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  virtual bool on_key(KEY key);

public:
  void load_prod_file(const char * nomefile, bool savefile, bool only_errors, TArray & warn_perc, TString_array & warning);
	void display_error(TViswin & v, const char * msg, TTracciato_record & t, TRecord_text & r);
	void print_record(TViswin & v, TTipo_rec t , TProduzione & r);
  TRilprod_mask();
	virtual ~TRilprod_mask() {}

};

TRilprod_mask::TRilprod_mask() : TAutomask("mr0500a")
{
	enable(F_DATALOG, main_app().has_module(POAUT, CHK_DONGLE));
	sfield(F_TEMPI).set_append(false);
}

bool TRilprod_mask::on_key(KEY key)
{
  //shift+f12 per abilitare il riquadro della bolla di produzione
  if (key == K_SHIFT + K_F12)
  {
    enable(-GR_BOLPROD);
    return true;
  }
  return TAutomask::on_key(key);
}

bool TRilprod_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  bool ok = true;
  switch (o.dlg())
  {
  case F_TEMPI:
		if (e == se_notify_add || e == se_notify_del)
		{
			TSheet_field & sh = (TSheet_field &)o;
			TMask_field & q = field(F_QTA);
			TMask_field & s = field(F_SCARTO);
			const int items = sh.items();
			const bool enable = items == 0;
			
			if (enable)
			{
				q.enable(); q.reset();
				s.enable(); s.reset();
			}
			else
			{
				q.disable();
				s.disable();
			}
		}
		else
			if (e == se_leave)
			{
				TSheet_field & sh = (TSheet_field &)o;
				TMask_field & q = field(F_QTA);
				TMask_field & s = field(F_SCARTO);
				const int items = sh.items();
				if (items > 0)
				{
					real qta;
					real scarto;

					for (int i = 0; i < items; i++)
					{
						TToken_string & r = sh.row(i);
						
						qta += (real)r.get(sh.cid2index(FR_QTA));
						scarto += (real)r.get(sh.cid2index(FR_SCARTO));
					}
					q.set(qta.string());
					s.set(scarto.string());
				}
			}
		break;
  case FR_ORAINI :
  case FR_MININI :
  case FR_SECINI :
  case FR_ORAFIN :
  case FR_MINFIN :
  case FR_SECFIN :
    if (e == fe_modify || e == fe_close)
    {
      //i campi ore/min/sec vanno zero filled
      TString8 stringa;
			if (o.get().not_empty())
			{
	      int numero = atoi(o.get());
		    stringa.format("%02d", numero);
				o.set(stringa);
			}
    }
    break;
  case H_PROG :
		if (e == fe_modify && key_valid(1))
			stop_run(K_AUTO_ENTER);
		break;
  case DLG_ELABORA :
    if (e == fe_button)
		{
			TElabora_mask m;

			if (m.run() == K_ENTER)
			{
				TConsuntivazione_produzione c(m.get(F_CODICE_EL));
				TLista_documenti docs;
				TDate d(m.get(F_DATA_EL));

				if (c.elabora(docs, docs, d, true))
					docs[0].rewrite();
			}
		}
		break;
  case F_DATALOG :
    if (e == fe_button)
		{
			TLoadfile_mask m;
			TArray warn_perc;
			TString_array warning;

			if (m.run() == K_ENTER)
			{
				{
					short dlg = F_PERC1;

					for (int i = 0; i < 4; i++)
					{
						const real perc(m.get(dlg++));

						warn_perc.add(perc);

						const TString & s = m.get(dlg++);

						warning.add(s); 
					}
				}
				load_prod_file(m.get(F_FILE), m.get_bool(F_SAVE), m.get_bool(F_ONLY_ERRORS), warn_perc, warning);
			}
		}
  default: 
    break;
  }
  return ok;
}

void TRilprod_mask::display_error(TViswin & v, const char * msg, TTracciato_record & t, TRecord_text & r)
{
  TString riga;
	const int nfields = t.tracciati_campo().items();

  v.add_line("");
	v.add_line(format(FR("Errore : %s"), msg));
	TString l;
	for (int f = 0; f < nfields; f++)
	{
		const TTracciato_campo & c = t.get(f);
		const TString & name = c.name();
		TString  val(r.get(f));
		TString s;
		
		val.trim();
		s.format(" %s = %s", (const char *) name,  (const char *) val);

		if (l.len() + s.len() > 80)
		{
			v.add_line(l);
			l.cut(0);
		}
		l << s;
	}
	if (l.not_empty())
		v.add_line(l);
}

void TRilprod_mask::print_record(TViswin & v, TTipo_rec t , TProduzione & r)
{
  TString riga;
	const int nfields = r.rec_des()->NFields;

  v.add_line("");
	if (t == _start)
		v.add_line(TR("Record elaborato - inizio produzione"));
	else
		if (t == _end)
			v.add_line(TR("Record elaborato - fine produzione"));
		else
			if (t == _rett)
				v.add_line(TR("Record elaborato - rettifica"));
	TString l;
	for (int i = 0; i < nfields; i++)
	{
		const TString & name = r.fieldname(i);
		const TString & val = r.get(name);

		TString s;
		
		s.format(" %s = %s", (const char *) name,  (const char *) val);

		if (l.len() + s.len() > 80)
		{
			v.add_line(l);
			l.cut(0);
		}
		l << s;
	}
	if (l.not_empty())
		v.add_line(l);
}

void TRilprod_mask::load_prod_file(const char * nomefile, bool savefile, bool only_errors, TArray & warn_perc, TString_array & warning)
{                
  TViswin vwin(NULL, TR("Importazione produzione"), FALSE, TRUE, TRUE);
  TFile_text prod(nomefile,"mr0500a.ini");         //crea un oggetto articoli di tipo TFile_text
  TRecord_text rec;                             //crea un record vuoto con nome articolocor 
	TTracciato_record & trec = *(prod.t_rec(""));
	const int nfields = trec.tracciati_campo().items();
	int type_field = 0;
	int ord_field = 0;
	int cod_field = 0;
  TProduzione prd;
  TLocalisamfile rigaord(LF_RIGHEDOC);
	TString val;
	TString codart;
	TLocalisamfile fp(LF_RILPROD);
	TRectype cmp(fp.curr());
	const long max = fsize(nomefile);
	TProgind p(max, format(FR("Importazione produzione : file %s"), nomefile));

	for (int f = 0; f < nfields; f++)
	{
		const TTracciato_campo & c = trec.get(f);
		const TString name = c.name();

		if (name == "TIPO")
			type_field = f;
		else
			if (name == "ORDINE")
				ord_field = f;
			else
				if (name == "CODART")
					cod_field = f;
  }                                                       
  vwin.open_modal();
  prod.open();                  //applico il metodo open che apre il file in lettura (contenuta in TFile_text)
	while(prod.ok_r())             //ok_r � una funzione che indica la fine del file
  { 
    if(prod.read(rec) == NOERR)
    {
			const TTipo_rec tipo = (TTipo_rec) atoi(rec.get(type_field));

			p.setstatus(prod.read_file()->tellg());
			if (tipo == _no_type)
			{
				display_error(vwin, TR("Tipo record non valido - record scartato"), trec, rec);
				continue;
			}

			const TString ordval(rec.get(ord_field));

			if (ordval.blank())
			{
				display_error(vwin, TR("Record vuoto - record scartato"), trec, rec);
				continue;
			}
			if (ordval.find('.') < 0)
			{
				display_error(vwin, TR("Riga ordine errata - record scartato"), trec, rec);
				continue;
			}

			TToken_string ord(ordval, '.');	ord.trim();
			const TString codnum(ord.get(0));
			const int anno = ord.get_int();
			const int ndoc = ord.get_long();
			const int nriga = ord.get_int();
			TDate d;
			TString h;
			real qta;
			real scarto;


			rigaord.zero();
			rigaord.put("CODNUM", codnum);
			rigaord.put("ANNO", anno);
			rigaord.put("PROVV", "D");
			rigaord.put("NDOC", ndoc);
			rigaord.put("NRIGA", nriga);

			codart.cut(0);
			TDate datao(TODAY);

			if (rigaord.read(_isequal) != NOERR)
				display_error(vwin, TR("Riga ordine inesistente"), trec, rec);
			else
			{
				codart = rigaord.get("CODART");
				TToken_string key;
				key.add("D");
				key.add(anno);
				key.add(codnum);
				key.add(ndoc);

				const TRectype  & doc = cache().get(LF_DOC, key);
				datao = doc.get_date("DATADOC");
			}
			TString codart_new(rec.get(cod_field));	codart_new.trim();
			const int err = prd.read_ordp(codnum, anno, 'D', ndoc, nriga);
			TDate datarec;
			bool nuovo = (err != NOERR);
			if (!nuovo)
			{
				fp.setkey(4);
				cmp.zero();
				cmp.put("CODNUM", codnum);
				cmp.put("ANNO", anno);
				cmp.put("PROVV", "D");
				cmp.put("NDOC", ndoc);
				cmp.put("NRIGA", nriga);
				fp.curr() = cmp;
				if (codart_new.not_empty())
				{
					nuovo = true;
					for (int err = fp.read(); (err == NOERR) && (fp.curr() == cmp);	err = fp.next())
					{
						if (codart_new == fp.get("CODART"))
						{
							nuovo = false;
							datarec = fp.get_date("DATA");
							break;
						}
					}
				}
				else
				{
					TRecnotype r = -1L;
					for (int err = fp.read(); (err == NOERR) && (fp.curr() == cmp);	err = fp.next())
					{
						const TRecnotype pos = fp.recno();
						if (r < pos)
							r = pos;
					}
					if (r >= 0L)
					{
						fp.readat(r);
						codart_new = fp.curr().get("CODART");
						datarec = fp.get_date("DATA");
					}
				}
			}
			if (codart_new.empty())
			{
				display_error(vwin, TR("Articolo nullo - record scartato"), trec, rec);
				continue;
			}
			else
			{
				const TRectype & anamag = cache().get(LF_ANAMAG, codart_new);

				if (anamag.empty())
				{
					display_error(vwin, TR("Articolo inesistente - record scartato"), trec, rec);
					continue;
				}
			}

			if (nuovo)
			{
				prd.zero();
				prd.put("CODNUM", codnum);
				prd.put("ANNO", anno);
				prd.put("PROVV", "D");
				prd.put("NDOC", ndoc);
				prd.put("NRIGA", nriga);
				prd.put("DATA", datao);
			}
			else
				prd.read_art(codart_new, datarec, 0);

			for (int f = 0; f < nfields; f++)
			{
				const TTracciato_campo & c = trec.get(f);
				const TString name = c.name();
				
				val = rec.get(f);
				val.trim();

				if (!val.empty() || tipo == _rett)
				{
					if (name == "TIPO" || name == "ORDINE")
						continue;
					else
						if (name == "DATA")
						{ 
							if (val.len() == 8)
								val.insert("20", 6);
							d = val;
						}
						else
							if (name == "ORA")
							{ 
								h = val.left(2);
								h << val.mid(3, 2) << val.right(2);
							}
							else
								if (name == "QTA")
									qta = (real) val;
								else
									if (name == "SCARTO")
										scarto = (real) val;
									else
										prd.put(name, val);
				}

      }
			if (prd.get("IMPIANTO").empty())
			{
				const TString16 linea(prd.get("LINEA"));
				if (linea.not_empty())
				{
					const TLinea_prod lp(linea);
					const TString16  imp(lp.codimp());
					if (imp.not_empty())
						prd.put("IMPIANTO", imp);
				}
			}
			if (!only_errors)
				print_record(vwin, tipo, prd);
			if (tipo == _start)
			{
				const int rows = prd.body().rows();
				bool found = false;
				bool seq_err = false;

				for (int i = 1; !found && i <= rows; i++)
				{
					const TRectype & row = prd.body()[i];
					found = d == row.get_date("DATAINI") && h == row.get("ORAINI");
					if (row.get("DATAFINE").empty())
						seq_err = true;
				}
				if (seq_err)
        		display_error(vwin, TR("Inizio senza fine precedente"), trec, rec);
				if (!found)
				{
					TRectype & row = prd.body().row(rows + 1, true);
					row.put("DATAINI", d);
					row.put("ORAINI", h);
				}
				if (nuovo)
					prd.write();
				else
					prd.rewrite();
			}
			else
				if (tipo == _end)
				{
					const int rows = prd.body().rows();
					bool found = false;

          int i;
					for (i = rows; i > 0; i--)
					{
						const TRectype & row = prd.body()[i];
						found = (d == row.get_date("DATAFINE") && h == row.get("ORAFINE")) ||
										row.get("DATAFINE").empty();
						if (found)
							break;
					}
					if (!found)
					{
						TRectype & row = prd.body().row(rows + 1, true);
						i = rows + 1;
        		display_error(vwin, TR("Fine senza inizio"), trec, rec);
					}
					TRectype & row = prd.body()[i];

					row.put("DATAFINE", d);
					row.put("ORAFINE", h);
					
					real diff = qta - row.get_real("QTA");
					real tot = prd.get_real("QTA") + diff;
					
					row.put("QTA", qta);
					prd.put("QTA", tot);
					diff = scarto - row.get_real("SCARTO");
					tot = prd.get_real("SCARTO") + diff;
					row.put("SCARTO", scarto);
					prd.put("SCARTO", tot);
					prd.rewrite();
				}
				else
				{
					const int rows = prd.body().rows();

					for (int i = 1; i <= rows; i++)
					{
						TRectype & row = prd.body()[i];
						if (i < rows)
						{
							row.zero("QTA");
							row.zero("SCARTO");
						}
						else
						{
							row.put("QTA", qta);
							row.put("SCARTO", scarto);
						}
					}
					prd.put("QTA", qta);
					prd.put("SCARTO", scarto);
					prd.rewrite();
				}
			
      if (tipo > _start) // Controllo lo scarto solo dopo  _start
      {
			  const real tot(prd.get_real("QTA") + prd.get_real("SCARTO"));
			  if (tot > ZERO)
			  {
				  real perc = prd.get_real("SCARTO") * CENTO / tot;

					perc.round(2);
				  for (int j = 3; j >= 0; j--)
				  {
					  if ((const real&)warn_perc[j] > ZERO && perc > (const real&)warn_perc[j])
					  {
							TString warn;

							warn.format("@b%s - percentuale %s", (const char *) warning.row(j), perc.string());
						  display_error(vwin, warn, trec, rec);
						  break;
					  }
				  }
			  }
      }
    }                                             
  }
	prod.close();
	if (savefile)
	{
		TFilename dest(nomefile);
		dest = dest.path();
		TString filemask(dest);
		TString_array arr;
		TDate filedate(TODAY);
		int cnt = 0;

		filemask << format("pr%02d%02d*.dat", filedate.month(), filedate.day());
		list_files(filemask, arr);

		const int items = arr.items();
		if (items > 0)
		{
			arr.sort();
			cnt = atoi(arr.row(items - 1).right(5));
		}
		cnt++;

		dest << format("pr%02d%02d%02d.dat", filedate.month(), filedate.day(), cnt);
		if (fcopy(nomefile, dest))
			remove_file(nomefile);

	}
  vwin.close_print();
  vwin.close_modal();  
  KEY k = vwin.run();
  if (k == K_CTRL+'S') // Ho premuto Stampa
    printer().print_txt(vwin.text());
}

///////////////////////////////////////////////////////////
// TRilprod_app
///////////////////////////////////////////////////////////

class TRilprod_app : public TRelation_application
{
  TRelation* _rel;
  TRilprod_mask* _msk;

  virtual int read( TMask& m );
  virtual int write( const TMask& m );
  virtual int rewrite( const TMask& m );
  virtual bool remove();

protected:
  virtual TMask* get_mask(int) { return _msk; }
  virtual TRelation* get_relation() const { return _rel; }
  virtual bool user_create();
  virtual bool user_destroy();
  virtual void init_insert_mode(TMask& m);
  virtual void init_modify_mode(TMask& m);
  virtual bool changing_mask (int) {return false; }
  virtual bool get_next_key(TToken_string& key);
};

void TRilprod_app::init_insert_mode(TMask& m)
{                
  m.disable(-GR_BOLPROD);
	m.field(F_QTA).enable();
	m.field(F_SCARTO).enable();
}

void TRilprod_app::init_modify_mode(TMask& m)
{                
  m.disable(-GR_BOLPROD);
}

bool TRilprod_app::user_create()
{
  _rel = new TRelation(LF_RILPROD);
  _msk = new TRilprod_mask();
  return true;
}

bool TRilprod_app::user_destroy()
{
  if (_msk != NULL)
    delete _msk;
  if (_rel != NULL)
    delete _rel;
  return true;
}

bool TRilprod_app::get_next_key(TToken_string& key)
{
  TMask& m = curr_mask( );
  
  if (m.get(F_CODART).empty() || m.get(F_DATA).empty())
    return false;

  TProduzione p;
	
  int n = 0;
  
  TLocalisamfile ril(LF_RILPROD);
  TRectype& curr = ril.curr();
	
	curr.put("CODART", m.get(F_CODART));
	curr.put("DATA", m.get_date(F_DATA));
  curr.put("PROG", 999);

  const int err = ril.read(_isgreat);
              
  if (err != _isemptyfile)
  {
    if (err == NOERR)
      ril.prev();
    if (curr.get("CODART") == m.get(F_CODART) && 
        curr.get("DATA") == m.get_date(F_DATA))
       n = curr.get_int("PROG");
  }     
  
  n++;

  key.format("%d|%d", F_PROG, n);
  return true;
}

int TRilprod_app::read( TMask& m )
{
	TProduzione p;
  int err = TRelation_application::read(m);
	
	if (err != NOERR)
		return err;
	p.TMultiple_rectype::read(_rel->curr());

	const int rows = p.body().rows();
	TSheet_field & sh = m.sfield(F_TEMPI);

	sh.reset();
	for (int i = 0 ; i < rows; i++)
	{
		TToken_string & r = sh.row(i);
		const TRectype & row = p.body()[i + 1];
		r.add(row.get("DATAINI"));
		const TString & oraini = row.get("ORAINI");
		r.add(oraini.left(2));
		r.add(oraini.mid(2, 2));
		r.add(oraini.right(2));
		r.add(row.get("DATAFINE"));
		const TString & orafin = row.get("ORAFINE");
		r.add(orafin.left(2));
		r.add(orafin.mid(2, 2));
		r.add(orafin.right(2));
		r.add(row.get("QTA"));
		r.add(row.get("SCARTO"));
	}

	const bool on = m.sfield(F_TEMPI).items() == 0;

	m.field(F_QTA).enable(on);
	m.field(F_SCARTO).enable(on);
  return NOERR;
}

int TRilprod_app::write( const TMask& m )
{   
	TProduzione p;
	TSheet_field & sh = m.sfield(F_TEMPI);
	const int rows = sh.items();

	p.zero();
	m.autosave(*_rel);
	p.head() = _rel->curr();
	for (int i = 0 ; i < rows; i++)
	{
		TToken_string & r = sh.row(i);
		TRectype & row = p.body().row(i + 1, true);
		
		row.put("DATAINI", r.get(0));
		TString8 ora(r.get());
		TString8 w(r.get());
		if (w.blank())
			w = "00"; 
		ora << w;
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		row.put("ORAINI", ora);
		row.put("DATAFINE", r.get());
		ora = r.get();
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		row.put("ORAFINE", ora);
		row.put("QTA", r.get());
		row.put("SCARTO", r.get());
	}
  const int err = p.write();
	
	_rel->curr() = p.head();
	_rel->read();
	return err;
}

int TRilprod_app::rewrite( const TMask& m )
{
	TProduzione p;
	TSheet_field & sh = m.sfield(F_TEMPI);
	const int rows = sh.items();

	m.autosave(*_rel);
	p.TMultiple_rectype::read(_rel->curr());
	p.head() = _rel->curr();
	p.destroy_rows();
	for (int i = 0 ; i < rows; i++)
	{
		TToken_string & r = sh.row(i);
		TRectype & row = p.body().row(i + 1, true);
		
		row.put("DATAINI", r.get(0));
		TString16 ora(r.get());
		TString8 w(r.get());
		if (w.blank())
			w = "00"; 
		ora << w;
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		row.put("ORAINI", ora);
		row.put("DATAFINE", r.get());
		ora = r.get();
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		w = r.get();
		if (w.blank())
			w = "00"; 
		ora << w;
		row.put("ORAFINE", ora);
		row.put("QTA", r.get());
		row.put("SCARTO", r.get());
	}
  return p.rewrite();
}

bool TRilprod_app::remove()
{
	TProduzione p;

	_msk->autosave(*_rel);
	p.TMultiple_rectype::read(_rel->curr());
  return p.remove() == NOERR;
}

int mr0500(int argc, char* argv[])
{
  TRilprod_app app;
  app.run(argc, argv, TR("Rilevazione Produzione"));
  return 0;
}