#include <applicat.h>
#include <automask.h>
#include <defmask.h>
#include <progind.h>
#include <relation.h>
#include <textset.h>
#include <utility.h>

#include "rdoc.h"
#include "../mr/rilprod.h"
#include "../mr/rrilprod.h"
#include "../ve/velib.h"

#include "ps1002.h"
#include "ps1002200a.h"

                                 ///////////////////////////////////
                                 ////    TACQUISIZIONE_CACHE    ////
                                 ///////////////////////////////////

//classe TAcquisizione_cache
class TBEM_cache : public TCache
{
  TString4 _codnum;

protected:
	virtual void discarding(const THash_object* obj);
  virtual TObject* key2obj(const char* key);

public:
  TDocumento& doc(const int anno, const TString4 codnum, const long ndoc);
  TBEM_cache();
};

//DISCARDING: metodo che salva un documento sul disco prima di eliminarlo dalla cache
void TBEM_cache::discarding(const THash_object* obj)
{
  TDocumento& doc = (TDocumento&)obj->obj();
  int err = doc.rewrite();
}

//KEY2OBJ: metodo che sceglie il documento giusto da disco in modo da poterlo continuare
TObject* TBEM_cache::key2obj(const char* key)
{
  TToken_string chiave(key);  
  //chiave di doc
  TString query;
  query << "USE DOC\n"
        << "FROM PROVV=D ANNO=" << chiave.get_int(0) << " CODNUM=" << chiave.get(1) << " NDOC=" << chiave.get_int(2) << "\n"
        << "TO PROVV=D ANNO=" << chiave.get_int(0) << " CODNUM=" << chiave.get(1) << " NDOC=" << chiave.get_int(2);
  TISAM_recordset rset(query);
  
  TDocumento* doc = NULL;

  if (rset.move_first())
    doc = new TDocumento(rset.cursor()->curr());
  
  return doc;
}

//DOC: metodo che restituisce un puntatore ad un documento identificato dalla chiave doc
TDocumento& TBEM_cache::doc(const int anno, const TString4 codnum, const long ndoc)
{
  TToken_string kdoc;
  kdoc.add(anno);
  kdoc.add(codnum);
  kdoc.add(ndoc);
  return *(TDocumento*)objptr(kdoc);
}

//metodo costruttore di una cache di 20 elementi
TBEM_cache::TBEM_cache() : TCache(20) 
{
}


                            ///////////////////////////////////////
                            ////    TIMPORTA_PRODUZIONE_REC    ////
                            ///////////////////////////////////////

//Classe TImporta_produzione_rec
class TImporta_produzione_rec: public TAS400_recordset
{
public:  
  TImporta_produzione_rec(const char* filename);
};

TImporta_produzione_rec::TImporta_produzione_rec(const char* filename)
                       : TAS400_recordset(TString("AS400(83)\n") << filename)
{
  create_field("RDOCKEY",  -1,  17,  _alfafld,    true);  //chiave di RDOC
  create_field("CODART",   -1,  20,  _alfafld,    true);  //codice articolo
  create_field("CODLAV",   -1,  10,  _alfafld,    true);  //codice lavorazione
  create_field("QTAPROD",  -1,  15,  _realfld,    true);  //quantit� prodotta  
  create_field("FLGSALDO", -1,   1,  _alfafld,    true);  //flag a saldo
  create_field("DATALAV",  -1,  10,  _alfafld,    true);  //data lavorazione
  create_field("ORALAV",   -1,   8,  _alfafld,    true);  //ora lavorazione
}

                            ///////////////////////////////////////
                            ////    TIMPORTA_PRODUZIONE_MSK    ////
                            ///////////////////////////////////////

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

	const int id2rownum(TDocumento& doc, long id) const;

  int  calcola_prog(const TString& codart, const TDate& data);
  int  calcola_nriga(const TString& codart, const TDate& data, const long prog);
  bool genera_produzione(const TFilename& file);
  void sposta_file(const TString& file);
  bool chiudi_bem();

public:
  bool importa_file();
  TImporta_produzione_msk();
};

bool TImporta_produzione_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
	switch (o.dlg())
	{
  case DLG_OK:
  case DLG_ELABORA:
    if(e == fe_button)
    {
      importa_file();
      return true;
    }
    break;
  default: break;
  }
  return true;
}

//CALCOLA_PROG: data la coppia articolo - data, calcola il progressivo successivo per completare la chiave
int TImporta_produzione_msk::calcola_prog(const TString& codart, const TDate& data)
{
  TString query;
  query << "USE RILPROD\n"
        << "FROM CODART=#CODART DATA=#DATA\n"
        << "TO CODART=#CODART DATA=#DATA\n"
        << "BY PROG";

  TISAM_recordset rilprod(query);
  rilprod.set_var("#CODART", codart);
  rilprod.set_var("#DATA",   data);

  int prog = 1;

  if(rilprod.move_last())
    prog += rilprod.get(RILPROD_PROG).as_int();
  return prog;
}

//CALCOLA_NRIGA: data la terna articolo - data - prog, calcola il numero riga successivo per completare la chiave
int TImporta_produzione_msk::calcola_nriga(const TString& codart, const TDate& data, const long prog)
{
  TString query;
  query << "USE RRILPROD\n"
        << "FROM CODART=#CODART DATA=#DATA PROG=#PROG\n"
        << "TO CODART=#CODART DATA=#DATA PROG=#PROG\n"
        << "BY NRIGA";

  TISAM_recordset rrilprod(query);
  rrilprod.set_var("#CODART", codart);
  rrilprod.set_var("#DATA",   data);
  rrilprod.set_var("#PROG",    prog);

  int nriga = 1;

  if(rrilprod.move_last())
    nriga += rrilprod.get(RRILPROD_NRIGA).as_int();
  return nriga;
}

//SPOSTA_FILE: archivia i file elaborati
void TImporta_produzione_msk::sposta_file(const TString& file)
{
  TFilename fileori = file;
  TFilename path = fileori.path();
  path.add("elaborati");
  make_dir(path);

  TString strname;
  strname.format("%06d_%06d_%s", TDate(TODAY).date2ansi(), daytime(), (const char*)fileori.name());  
  TFilename filedest = path;
  filedest.add(strname);
  fcopy(fileori, filedest);
  fileori.fremove();
}

const int TImporta_produzione_msk::id2rownum(TDocumento& doc, long id) const
{
  FOR_EACH_PHYSICAL_RDOC_BACK(doc, r, row)
  {
    if (row->get_long(RDOC_IDRIGA) == id)
      return row->get_int(RDOC_NRIGA);
  }
  return -1;
}

bool TImporta_produzione_msk::chiudi_bem()
{
    const TDate data = get_date(F_DATA);
  
  TLocalisamfile rilprod(LF_RILPROD);
  TBEM_cache ca;

  int err = NOERR;

  TString query;
  query << "USE RILPROD KEY 5";
  if(data.ok())
    query << "\nSELECT DATA<=#DATA";
  query << "\nFROM PROVV=\"\" ANNOP=\"\" CODNUMP=\"\" NDOCP=\"\" NRIGAP=\"\""
        << "\nTO PROVV=\"\" ANNOP=\"\" CODNUMP=\"\" NDOCP=\"\" NRIGAP=\"\"";

  TISAM_recordset testate(query);
  if(data.ok())
    testate.set_var("#DATA", data);

  for(bool ok = testate.move_first(); ok; ok = testate.move_next())
  {
    TRectype& trec = testate.cursor()->curr();
    const char      provv  = trec.get(RILPROD_PROVV)[0];
    const int       anno   = trec.get_int(RILPROD_ANNO);
    const TString4  codnum = trec.get(RILPROD_CODNUM);
    const int       ndoc   = trec.get_long(RILPROD_NDOC);
    const int       idriga = trec.get_int(RILPROD_NRIGA);
    const real      qta    = trec.get_real(RILPROD_QTA);
    const TString16 codlav = trec.get(RILPROD_OPERATORE);
    const TDate     data   = trec.get_date(RILPROD_DATA);

    TString query;
    query << "USE DOC\n"
          << "FROM PROVV=D ANNO=" << anno << " CODNUM=" << codnum << " NDOC=" << ndoc << "\n"
          << "TO PROVV=D ANNO="   << anno << " CODNUM=" << codnum << " NDOC=" << ndoc;
    TISAM_recordset rset(query);
    
    if(rset.items == 0)
    {
      TString str;
      str << "ATTENZIONE. Il documento " << codnum << '-' << ndoc << " non esiste!";
      warning_box(str);
      continue;
    }
    
    TDocumento& doc = ca.doc(anno, codnum, ndoc);
    if(!doc.empty())
    {
      const int nriga = id2rownum(doc, idriga);
      TRiga_documento& row = doc[nriga];

      if(row.get(RDOC_FASCMS) == codlav)
      {
        row.put(RDOC_DATACONS, data.string());
        row.put(RDOC_QTAGG1,   qta);
      }
      else if(row.get(RDOC_CODCMS) == codlav)
      {
        row.put(RDOC_CODAGG2, data.string());
        row.put(RDOC_QTAGG2,  qta);
      }
      else
        warning_box(TR("Riga BEM non trovata"));

      trec.put(RILPROD_PROVVP,  provv);
      trec.put(RILPROD_ANNOP,   anno);
      trec.put(RILPROD_CODNUMP, codnum);
      trec.put(RILPROD_NDOCP,   ndoc);
      trec.put(RILPROD_NRIGAP,  idriga);
      trec.rewrite(rilprod);
    }
    else
      return false;
  }
  ca.destroy();
  return true;
}

//GENERA_PRODUZIONE: effettiva elaborazione del file
bool TImporta_produzione_msk::genera_produzione(const TFilename& file)
{
  int err = NOERR;
  TImporta_produzione_rec recset(file);

  TProgind pi(recset.items(), "Importazione in corso...", true, true);

  TLocalisamfile tprod(LF_RILPROD);
  TLocalisamfile rprod(LF_RRILPROD);

  TAssoc_array tprod_ar;

  //scorro il file di input
  for(bool ok = recset.move_first(); ok; ok = recset.move_next())
  {
    if (!pi.addstatus(1)) 
		  break;
    
    //estraggo i dati di interesse
    TString80 chiavedoc = recset.get("RDOCKEY").as_string();
    TToken_string krdoc(chiavedoc, '.');
    const TString80     codart   = recset.get("CODART").as_string();
    TString16           codlav   = recset.get("CODLAV").as_string();
    const real          qtaprod  = recset.get("QTAPROD").as_real();
    const bool          flgsaldo = recset.get("FLGSALDO").as_string()[0] == 'S' ? true : false;
    const TString16     datastr  = recset.get("DATALAV").as_string();
    const TString8      orastr   = recset.get("ORALAV").as_string();

		if(datastr.blank())
			continue;

    const char provv = 'D';   
    TString80 codnum = krdoc.get(0);
    const int      anno   = krdoc.get_int(1);
    const long     ndoc   = krdoc.get_long(2);
    const int      idriga = krdoc.get_int(3);

    const TDate    datafine(atoi(datastr.left(2)), atoi(datastr.mid(3,2)), atoi(datastr.right(4)));
    TString8 orafine(orastr); orafine.strip(":");

    TToken_string key;
    key.add(codart);
    key.add(codlav);
    key.add(chiavedoc.strip("."));

    int prog;


    TString query;
		query << "USE RRILPROD\n"
          << "SELECT (DATAINI==\"" << datafine << "\")&&(ORAINI==\"" << orafine << "\")\n"
          << "FROM CODART="  << codart << " DATA=#DATA\n"
          << "TO CODART="  << codart << " DATA=#DATA";
    TISAM_recordset righe(query);
    righe.set_var("#DATA", datafine);
    if(righe.items() > 0)
      continue;

    query.cut(0);
		query << "USE RILPROD KEY 4\n"
          << "SELECT OPERATORE==\"" << codlav.strip(" ") << "\"\n"
          << "FROM PROVV=D ANNO=" << anno << " CODNUM=" << codnum.strip(" ") << " NDOC=" << ndoc << " NRIGA=" << idriga << "\n"
					<< "TO PROVV=D ANNO=" << anno << " CODNUM=" << codnum.strip(" ") << " NDOC=" << ndoc << " NRIGA=" << idriga;
		TISAM_recordset testate(query);
		
    if(testate.items() > 0)
		{
      TRectype& testata = testate.cursor()->curr();
      real& qta = testata.get_real(RILPROD_QTA);
      prog = testata.get_int(RILPROD_PROG);
      qta += qtaprod;
      testata.put(RILPROD_QTA, qta);
      tprod_ar.add(key, testata);
      err = testata.rewrite_write(tprod);
		}
    else if(!tprod_ar.is_key(key))
    {
      query.cut(0);
      query << "USE RILPROD KEY 4 SELECT OPERATORE==\"" << codlav.strip(" ") << "\"\n"    
            << "BY PROG\n"
			      << "FROM PROVV=D ANNO=" << anno << " CODNUM=" << codnum.strip(" ") << " NDOC=" << ndoc << "\n"
					  << "TO PROVV=D ANNO=" << anno << " CODNUM=" << codnum.strip(" ") << " NDOC=" << ndoc;
		  TISAM_recordset testate1(query);

      prog = 1;

      if(testate1.items() > 0)
      {
        testate1.move_last();
        TRectype& testata = testate1.cursor()->curr();
        prog = testata.get_int(RILPROD_PROG);
        prog++;
      }
      else
      {
        query << "USE RILPROD\n"    
            << "BY PROG\n"
            << "FROM CODART=" << codart << "DATA=#DATA\n"
					  << "TO CODART=" << codart << "DATA=#DATA";
		    TISAM_recordset testate1(query);
        testate1.set_var("#DATA", datafine);

        testate1.move_last();
        TRectype& testata = testate1.cursor()->curr();
        prog = testata.get_int(RILPROD_PROG);
        prog++;
      }

      //se non l'ho gi� fatto creo il record della testata, altrimenti aggiorno le quantit�
      TRectype& testata = tprod.curr();
      testata.zero();
      testata.put(RILPROD_CODART,    codart);
      testata.put(RILPROD_DATA,      datafine);
      testata.put(RILPROD_PROG,      prog);
      testata.put(RILPROD_CODNUM,    codnum);
      testata.put(RILPROD_ANNO,      anno);
      testata.put(RILPROD_PROVV,     provv);
      testata.put(RILPROD_NDOC,      ndoc);
      testata.put(RILPROD_NRIGA,     idriga);
      testata.put(RILPROD_OPERATORE, codlav);
      testata.put(RILPROD_QTA,       qtaprod);
      testata.put(RILPROD_CHIUSO,    flgsaldo);

      err = testata.rewrite_write(tprod);

      tprod_ar.add(key, testata);
    }
    else
    {
      TRectype& testata = *(TRectype*)tprod_ar.objptr(key);
      real& qta = testata.get_real(RILPROD_QTA);
      qta += qtaprod;
      prog = testata.get_int(RILPROD_PROG);
      testata.put(RILPROD_QTA, qta);
      err = testata.rewrite_write(tprod);
      tprod_ar.add(key, testata);
    }

    //creo la riga corrispondente a quella letta da file
    TRectype& riga = rprod.curr();
    riga.zero();
    riga.put(RRILPROD_CODART,    codart);
    riga.put(RRILPROD_DATA,      datafine);
    riga.put(RRILPROD_PROG,      prog);
    riga.put(RRILPROD_NRIGA,     calcola_nriga(codart, datafine, prog));
    riga.put(RRILPROD_OPERATORE, codlav);
    riga.put(RRILPROD_DATAINI,   datafine);
    riga.put(RRILPROD_ORAINI,    orafine);
    riga.put(RRILPROD_DATAFINE,  datafine);
    riga.put(RRILPROD_ORAFINE,   orafine);
    riga.put(RRILPROD_QTA,       qtaprod);

    err = riga.rewrite_write(rprod);
  }

  
  return err == NOERR ? true : false;
}

//IMPORTA_FILE: controlla l'esistenza del file e richiama le effettive elaborazioni
bool TImporta_produzione_msk::importa_file()
{
  const TFilename file = get(F_FILE);

  if(file.exist())
  {
    if(genera_produzione(file))
    {
      sposta_file(file);
      if(chiudi_bem())
        message_box(TR("Importazione terminata con successo"));
      else
        error_box(TR("Errore durante l'aggiornamento dei documenti"));
    }
    else
      error_box(TR("Errore durante l'importazione del file"));
  }
  else
  {
    error_box(TR("Il file selezionato non esiste; si prega di controllare"));
    return false;
  }
  return true;
}

TImporta_produzione_msk::TImporta_produzione_msk() 
                       : TAutomask ("ps1002200a")
{}

                            ///////////////////////////////////////
                            ////    TIMPORTA_PRODUZIONE_APP    ////
                            ///////////////////////////////////////

//Classe TImporta_produzione_app
class TImporta_produzione_app : public TSkeleton_application
{
protected:
	virtual bool check_autorization() const { return false; }
  virtual const char* extra_modules() const { return "ve"; }
  virtual void main_loop();
  virtual bool create();
};

void TImporta_produzione_app::main_loop()
{
  TImporta_produzione_msk mask;
  mask.run();
}

bool TImporta_produzione_app::create()
{  
  return TSkeleton_application::create();
}

int ps1002200 (int argc, char* argv[])
{
  TImporta_produzione_app main_app;
  main_app.run(argc, argv, TR("Importa produzione da terminale"));
  return true;
}