#include <applicat.h>
#include <automask.h>
#include <config.h>
#include <dongle.h>
#include <execp.h>
#include <lffiles.h>
#include <progind.h>
#include <recarray.h>
#include <reputils.h>
#include <textset.h>
#include <utility.h>

#include <doc.h>
#include <rdoc.h>
#include "../mg/anamag.h"
#include "../mg/umart.h"

#include "ps0398100a.h"

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

public:
  TTrasferimento_ordini_mask();
};

TTrasferimento_ordini_mask::TTrasferimento_ordini_mask() : TAutomask("ps0398100a")
{
}

bool TTrasferimento_ordini_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  /*switch(o.dlg())
  {
  default:
    break;
  }*/
  return true;
}

class TTrasferimento_ordini_recordset : public TCSV_recordset
{
public:
  TTrasferimento_ordini_recordset(const char* filename);
};


//////////////////////////////////////////////
//  RECORDSET
/////////////////////////////////////////////
//creazione del recordset di ogni ordine
TTrasferimento_ordini_recordset::TTrasferimento_ordini_recordset(const char* filename) : TCSV_recordset("CSV(\"\t\")")
{
  load_file(filename);
};


//////////////////////////////////////////////
//  APPLICAZIONE
/////////////////////////////////////////////
//Ridistributore di F24 per il computer
class TTrasferimento_ordini : public TSkeleton_application
{
  TTrasferimento_ordini_mask*  _mask;
  TString4 _codmag;

protected:
  virtual bool check_autorization() const {return false;}
  virtual const char * extra_modules() const {return "ve";}
  virtual bool create();
  virtual void main_loop();

public:
  bool ordine_gf(TTrasferimento_ordini_recordset& recset);
  void elab_hd_ht(const TString& riga_txt, const int curr_nriga, TString& str);
  void elab_hf(const TString& riga_txt, const int curr_nriga, TConfig& curr_ini, TLog_report& log, TString& ragsoc);
  void elab_ho(const TString& riga_txt, const int curr_nriga, TConfig& curr_ini, TLog_report& log, TString& ho_note_generali);
  void elab_ra(const TString& riga_txt, const int curr_nriga, TConfig& curr_ini, TLog_report& log);
  bool elabora_file_txt(TTrasferimento_ordini_recordset& recset, const TFilename& ini_fname, TLog_report& log);
  bool sposta_file_elaborato(const TFilename& dst_file, const TFilename& curr_fname, TLog_report& log);
  bool elabora();
};


//metodo per scoprire se l'ordine � di GF o no
bool TTrasferimento_ordini::ordine_gf(TTrasferimento_ordini_recordset& recset)
{
  //le righe articolo o sono tutte di GF o non lo sono (nessuna situazione mista)
  bool is_ordine_gf = false;

  for (bool ok = recset.move_last(); ok; ok = recset.move_prev())
  {
    const TString& riga_txt = recset.get(0L).as_string();
    const TString& tr = riga_txt.left(2);
    if (tr == "RA")
    {
      TToken_string riga_ord(riga_txt.mid(5), ';');
      const TString& codart = riga_ord.get();
      //se il codice articolo non contiene il carattere '.' -> non � di GF -> scartato
      const int dot_pos = codart.find('.');
      if (dot_pos >= 0)
      {
        is_ordine_gf = true;
        break;
      }
    }
  }
  return is_ordine_gf;
}

void TTrasferimento_ordini::elab_hf(const TString& riga_txt, const int curr_nriga, 
                                    TConfig& curr_ini, TLog_report& log, TString& ragsoc)
{
  switch (curr_nriga)
  {
  case 1:
    {
      ragsoc = riga_txt.mid(5);
      ragsoc.trim();
      ragsoc.cut(50);
    }
    break;
  case 6:
    {
      const long codcf = atol(riga_txt.mid(14,6));
      //per prima cosa controlla se � possibile risalire al cliente che ha generato l'ordine..
      //..no cliente...no party!
      if (codcf <= 0)
      {
        TString msg;
        msg.format("Il cliente %s ha codice nullo!", (const char*)ragsoc);
        log.log(2, msg);
      }
      else
      {
        TString4 head_paragrafo;
        head_paragrafo << LF_DOC;
        curr_ini.set(DOC_TIPOCF, "C", head_paragrafo);
        curr_ini.set(DOC_CODCF, codcf, head_paragrafo);
      }
    }
    break;
  default:
    break;
  }
}


void TTrasferimento_ordini::elab_hd_ht(const TString& riga_txt, const int curr_nriga, 
                                       TString& str)
{
  if (riga_txt.full())
  {
    switch (curr_nriga)
    {
    case 3:
    case 4:
      str << riga_txt;
      str.strip_double_spaces();
      str << "\\n";
      break;

    default:
      break;
    }
  }
}


void TTrasferimento_ordini::elab_ho(const TString& riga_txt, const int curr_nriga,
                                    TConfig& curr_ini, TLog_report& log, TString& ho_note_generali)
{
  switch (curr_nriga)
  {
  case 1: //numero ordine del sito web (per ora non serve, ma poi si vedr�...)
    {
      const long num_ord_web = atol(riga_txt.mid(5));
    }
    break;
  case 3: //datadoc (scritta alla cazzo)
    {
      TToken_string str_data(riga_txt.mid(5, 100).before(' '), '/');
      const TDate datadoc(str_data.get_int(0), str_data.get_int(1), str_data.get_int(2));
      if (!datadoc.ok())
      {
        TString msg;
        msg.format(FR("Data documento non valida: %s"), (const char*)str_data);
        log.log(2, msg);
      }
      TString4 head_paragrafo;
      head_paragrafo << LF_DOC;
      curr_ini.set(DOC_DATADOC, datadoc, head_paragrafo);
    }
    break;
  case 4: //altre note ordine (da mettere in DOC_NOTE)
    {
      ho_note_generali << riga_txt.mid(5);
      ho_note_generali.trim();
    }
    break;
  case 5: //codice condizione pagamento (anche questo x ora non serve, ma sempre si vedr�...)
    {
      const int cod_pag = atoi(riga_txt.mid(5));
    }
    break;
  default:
    break;
  } //switch(curr_nriga)
}


void TTrasferimento_ordini::elab_ra(const TString& riga_txt, const int curr_nriga,
                                    TConfig& curr_ini, TLog_report& log)
{
  TToken_string riga_ord(riga_txt.mid(5), ';');
  const TString codart = riga_ord.get();
  TString16 str_qta = riga_ord.get();
  str_qta.strip(". ");
  str_qta.replace(',', '.');

  //set_paragraph sulle righe (file 34, righedoc)
  TString8 row_paragrafo;
  row_paragrafo << LF_RIGHEDOC << ',' << curr_nriga;
  curr_ini.set_paragraph(row_paragrafo);
  
  curr_ini.set(RDOC_TIPORIGA, "01");
  //l'articolo deve esistere per stare in codartmag e codart;
  //se non esiste in anagrafica -> solo in codart con segnalazione
  //la desc riga sar� la desc articolo
  const TRectype& rec_anamag = cache().get(LF_ANAMAG, codart);
  //se il record � vuoto l'articolo non � in anagrafica
  if (rec_anamag.empty())
  {
    TString msg;
    msg = TR("Articolo non in anagrafica");
    curr_ini.set(RDOC_DESCR, msg);

    msg << ": " << codart;
    log.log(2, msg);
  }
  else  //senn� va tranquillo
  {
//    curr_ini.set(RDOC_CODARTMAG, codart);
    curr_ini.set(RDOC_DESCR, rec_anamag.get(ANAMAG_DESCR));
//    curr_ini.set(RDOC_CHECKED, "X");

    //alla qta associa la prima unit� di misura
    TToken_string key_umart;
    key_umart.add(codart);
    key_umart.add(1);
    const TRectype& rec_umart = cache().get(LF_UMART, key_umart);
    const TString& umqta = rec_umart.get(UMART_UM);
    curr_ini.set(RDOC_UMQTA, umqta);
  }
  //queste le fa in ogni modo (forse rischiando)
  curr_ini.set(RDOC_CODART, codart);
  curr_ini.set(RDOC_QTA, str_qta);

//  TString80 str_prezzo = riga_ord.get();   //per adesso ci si mette il prezzo sull'ordine
//  str_prezzo.replace(',', '.');
//  curr_ini.set(RDOC_PREZZO, str_prezzo);
  //e per ultime le eventuali note
  const TString nota = riga_ord.get();
  if (nota.full())
  {
    curr_ini.set(RDOC_DESCLUNGA, "X");
    curr_ini.set(RDOC_DESCEST, nota);
  }

  //anzi, per ultimissimo il magazzino
  curr_ini.set(RDOC_CODMAG, _codmag);
}


bool TTrasferimento_ordini::elabora_file_txt(TTrasferimento_ordini_recordset& recset, const TFilename& ini_fname,
                                             TLog_report& log)
{
  //variabili da riempire ad ogni giro
  TString4 curr_tiporiga;         //tipo riga in esame (HT...RA), ovvero sezione del file
  int curr_nriga = 0;             //n riga della sezione in esame
  TString ragsoc, piva;
  TString hd_spedizione;          //questi stanno qui perch� valgono una volta per file .txt
  TString ht_fatturazione;
  TString ho_note_generali;

  //creazione del file .ini di transazione
  TConfig curr_ini(ini_fname);

  curr_ini.set_paragraph("Transaction"); //setto il paragrafo [Transaction] del file ini
  curr_ini.set("Action","INSERT");
  curr_ini.set("Mode","");

  //set_paragraph sulle testate (file 33, doc)
  TString4 head_paragrafo;
  head_paragrafo << LF_DOC;
  curr_ini.set_paragraph(head_paragrafo);

  TToken_string tipi_record("HF|HD|HT|HS|HO|RA");

  //comincia il giro sulle righe del recordset
  //va al contrario perch� se le righe non hanno articoli di GF -> salta il tutto
  for (bool ok = recset.move_first(); ok; ok = recset.move_next())
  {
    //riga corrente del file di input
    const TString& riga_txt = recset.get(0L).as_string();

    //gestione cambio riga e cambio sezione
    const TString& tr = riga_txt.left(2);
    if (tipi_record.get_pos(tr) < 0)
    {
      if (curr_tiporiga == "HO")
      {
        //righe del cazzo senza capo; in teoria possono appartenere solo al campo NOTE di HO (in teoria, ovviamente)
        TString riga_del_cazzo = riga_txt;
        riga_del_cazzo.trim();
        ho_note_generali << " " << riga_del_cazzo;
      }
      continue;
    }

    if (tr != curr_tiporiga)
    {
      curr_tiporiga = tr;
      curr_nriga = 1;
    }
    else
      curr_nriga ++;

    //trattazione delle varie sezioni
    // HS (va saltata)
    if (curr_tiporiga == "HS")
      continue;

    // HF
    if (curr_tiporiga == "HF")
      elab_hf(riga_txt, curr_nriga, curr_ini, log, ragsoc);

    // HD
    if (curr_tiporiga == "HD")
      elab_hd_ht(riga_txt.mid(5, 100), curr_nriga, hd_spedizione);  //(note spedizione)

    // HT
    if (curr_tiporiga == "HT")
      elab_hd_ht(riga_txt.mid(5, 100), curr_nriga, ht_fatturazione);  //(note fatturazione)

    // HO
    if (curr_tiporiga == "HO")
      elab_ho(riga_txt, curr_nriga, curr_ini, log, ho_note_generali);

    // RA
    //gestione delle righe ordine
    if (curr_tiporiga == "RA")
      elab_ra(riga_txt, curr_nriga, curr_ini, log);

  } //for(bool ok=recset.move.frst...

  //scrive sul campo NOTE della testata quello che sa delle note spedizione e fatturazione
  TString note;
  note << '"';

  if (hd_spedizione.full())
    note << "Note Spedizione: " << hd_spedizione << "\\n";
  if (ht_fatturazione.full())
    note << "Note Fatturazione: " << ht_fatturazione << "\\n";
  if (ho_note_generali.full())
    note << "Note generali: " << ho_note_generali;

  note << '"';
  curr_ini.set(DOC_NOTE, note, head_paragrafo);

  //qui ci va il lancio di ve0 con l'ini generato
  curr_ini.set(DOC_PROVV, "D");
  curr_ini.set(DOC_CODNUM, _mask->get(F_CODNUM));
  const TDate datadoc = curr_ini.get(DOC_DATADOC);
  curr_ini.set(DOC_ANNO, datadoc.year());
  curr_ini.set(DOC_TIPODOC, _mask->get(F_TIPODOC));
  curr_ini.set(DOC_STATO, 1);

  return true;
}

bool TTrasferimento_ordini::sposta_file_elaborato(const TFilename& dst_file, const TFilename& curr_fname, 
                                                  TLog_report& log)
{
  bool copia_riuscita = fcopy(curr_fname, dst_file, false, true);
  if (copia_riuscita)
  {
    const long src_size = fsize(curr_fname);
    const long dst_size = fsize(dst_file);
		
		copia_riuscita = src_size == dst_size;
  }
  if (copia_riuscita) //se va tutto bene elimina il file dalla directory di origine
  {
#ifdef DBG
    if (noyes_box(FR("Si desidera eliminare il file remoto '%s'"), (const char*)curr_fname))
#endif
    if (!remove_file(curr_fname))
    {
      TString msg;
      msg.format("Impossibile eliminare il file origine '%s'", (const char*)curr_fname);
      log.log(1, msg);
    }
  }
  else  
  {
    TString msg;
    msg.format(FR("Impossibile copiare il file '%s'!"), curr_fname.name());
    log.log(2, msg);
  }
  return copia_riuscita;
}


bool TTrasferimento_ordini::elabora()
{
  TFilename src_files = _mask->get(F_PATH_SRC);
  src_files.add("*HEADER.txt");
  TString_array src_files_list;
  //dalla cartella origine prende tutti i files *HEADER.txt e crea una simpatica lista
  int n_files_txt = 0;
  if (src_files.full())
  {
    TWait_cursor hourglass;
    n_files_txt = list_files(src_files, src_files_list);
  }

  //gi� che c'� prende pure gli altri dati dalla maschera che gli servono poi
  TFilename dst_path = _mask->get(F_PATH_DST);

  //cartella dove saranno creati i .ini
  TFilename tmp;
  tmp.tempdir();
  tmp.add("ps0398");
  const bool crea_dir = make_dir(tmp);
  //non riesce a crearla! deve dare errore di grave livello!
  if (!crea_dir)
  {
    TString msg;
    msg.format(FR("Impossibile creare la cartella di lavoro %s!"), tmp);
    return error_box(msg);
  }

  //scansione dello string_array per il trasferimento (con tanto di progind e log)
  TProgind pi(n_files_txt, main_app().title(), true, true);

  TLog_report log(main_app().title());
  if (n_files_txt >= 0)
  {
    const bool pasv = ini_get_string(CONFIG_INSTALL, "Server", "ftp", "Passive")[0] != 'A';
    TString msg; 
    msg << src_files;
    log.log(0, msg);
    
    msg.cut(0) << n_files_txt << ' ' << TR("ordini da elaborare") << " (ftp " << (pasv ? "Passive" : "Active") << " mode)";
    log.log(n_files_txt<=0 ? 1 : 0, msg);
  }

  //si accatta anche il magazzino
  _codmag = _mask->get(F_CODMAG);

  //ciclo su tutti i files .txt da esaminare
  for (int i = 0; i < n_files_txt; i++)
  {
    if (!pi.addstatus(1))
      break;

    //file in formato filename (� l'ordine corrente da elaborare)
    const TFilename curr_fname = src_files_list.row(i);
		TFilename tempfile(tmp);
		tempfile.add(curr_fname.name());
		if (!fcopy(curr_fname, tempfile, false, true))
    {
      TString msg;
      msg << TR("Impossibile leggere il file ") << curr_fname;
      log.log(2, msg);
      continue;
    }
    //creazione del recordset associato al file
    TTrasferimento_ordini_recordset recset(tempfile);

    //se il file non � di GF (si vede dal codart) viene saltato! Hop!
    if (!ordine_gf(recset))
    {
      TString msg;
      msg << TR("File Scartato: ") << curr_fname;
      log.log(1, msg);
      continue;
    }

    //avverte sul log quale file sta elaborando
    TString msg;
    msg << TR("Elaborazione file ") << curr_fname;
    log.log(0, msg);

    //per ogni ordine in formato .txt genera un file.ini che andr� poi documentizzato
    //file .ini
    TFilename ini_fname = tmp;
    ini_fname.add(format("ORD%05ld.ini", i));
    //elaborazione del file .txt per riempireil .ini della successiva elaborazione differita
    bool elaborazione_ok = elabora_file_txt(recset, ini_fname, log);

    //elaborazione interattiva dell'ordine dal .ini
    if (elaborazione_ok)
    {
		  TString commandline;
		  commandline << "ve0 -0 /i" << ini_fname;
		  TExternal_app ve(commandline);
		  ve.run();
    }

    //qui ci va lo spostamento del file elaborato se ve0 ha funzionato correttamente
    TFilename dst_file = dst_path;
    dst_file.add(curr_fname.name());
    const bool copia_riuscita = sposta_file_elaborato(dst_file, curr_fname, log);
  } //for(int i...

  log.log(0, TR("Acquisizione ordini completata"));
  log.preview();

  return true;
}

bool TTrasferimento_ordini::create()
{
  Tdninst dninst;
  if (!dninst.can_I_run(true))
    return error_box(TR("Programma non autorizzato!"));
  return TSkeleton_application::create();
}

void TTrasferimento_ordini::main_loop()
{
  _mask = new TTrasferimento_ordini_mask;
  if (_mask->run() != K_QUIT)
    elabora();

  delete _mask;
  _mask = NULL;
}

int ps0398100 (int argc, char **argv)
{
  TTrasferimento_ordini a;
  a.run(argc,argv, TR("Acquisizione ordini web"));
  return true;
}