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

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

#include "ps0713400a.h"

#include "ps0713lib.h"
#include <../cg/cfban.h>

                                       ///////////////////////////////////
                                       ////    TIMPORTA_FATVEN_MSK    ////
                                       ///////////////////////////////////

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

public:
  TImporta_fatven_msk();
};
  
TImporta_fatven_msk::TImporta_fatven_msk() :TAutomask ("ps0713400a")
{
}  

//ON_FIELD_EVENT: metodo che gestisce i comportamenti dei vari campi della maschera
//(per adesso segnaposto)
bool TImporta_fatven_msk::on_field_event(TOperable_field& f, TField_event e, long jolly)
{
  return true;
}

                                       ///////////////////////////////////
                                       ////    TIMPORTA_FATVEN_APP    ////
                                       ///////////////////////////////////

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

  const TString& togli_apici(const TVB_recset& s, int i) const;
  long  togli_apici_numero(const TVB_recset& s, int i) const;
  const TString& togli_apici_descr(const TVB_recset& s, int i) const;
  long find_cliente(TLocalisamfile& clifo, const TString& cofi, const TString& paiv) const;
  void put_rdoc_descr(TRiga_documento& rdoc, const TString& descr) const;
  bool update_cfban(long codcf, const TVB_recset& s, int idx_abi) const;

public:           
	bool transfer(const TFilename& file);
  virtual void main_loop();
};

//TOGLI_APICI: metodo che restituisce un campo del recordset come stringa
//preoccupandosi prima di eliminare eventuali doppi apici
const TString& TImporta_fatven_app::togli_apici(const TVB_recset& s, int i) const
{
  const TString& str = s.get(i).as_string();
  if (str.starts_with("\""))
  {
    TString& tmp = get_tmp_string();
    tmp = str;
    tmp.strip("\"");
    tmp.trim();
    return tmp;
  }
  return str;
}

//TOGLI_APICI_NUMERO: metodo che restituisce un campo del recordset come numero
//preoccupandosi prima di eliminare eventuali doppi apici
long TImporta_fatven_app::togli_apici_numero(const TVB_recset& s, int i) const
{
  const TString& tmp = togli_apici(s, i);
  return atol(tmp);
}

//TOGLI_APICI: metodo che restituisce un campo del recordset come stringa
//preoccupandosi prima di eliminare eventuali doppi apici
const TString& TImporta_fatven_app::togli_apici_descr(const TVB_recset& s, int i) const
{
  TString& tmp = get_tmp_string();
  tmp = togli_apici(s, i);
  if (tmp.full())
  {
    tmp.replace(11, '\n');
    tmp.trim();
  }
  return tmp;
}


//FIND_CLIFO: metodo che cerca un cliente dati paiv e cofi
long TImporta_fatven_app::find_cliente(TLocalisamfile& clifo, const TString& paiv, const TString& ragsoc) const
{
  if (paiv.full())
  {
    clifo.setkey(5);
    clifo.zero();
    clifo.put(CLI_TIPOCF, 'C');
    clifo.put(CLI_PAIV, paiv);
    if (clifo.read() == NOERR)
      return clifo.get_long(CLI_CODCF);
    if (paiv.len() == 16)
    {
      clifo.setkey(4);
      clifo.zero();
      clifo.put(CLI_TIPOCF, 'C');
      clifo.put(CLI_COFI, paiv);
      if (clifo.read() == NOERR)
        return clifo.get_long(CLI_CODCF);
    }
  }
  if (ragsoc.full())
  {
    clifo.setkey(2);
    clifo.zero();
    clifo.put(CLI_TIPOCF, 'C');
    clifo.put(CLI_RAGSOC, ragsoc);
    if (clifo.read() == NOERR)
      return clifo.get_long(CLI_CODCF);
    
    TToken_string rs(ragsoc, ' ');
    if (rs.items() == 2)
    {
      TString cognom;
      cognom = rs.get(0); cognom.left_just(30);
      cognom << rs.get();
      clifo.zero();
      clifo.put(CLI_TIPOCF, 'C');
      clifo.put(CLI_RAGSOC, cognom);
      if (clifo.read() == NOERR)
        return clifo.get_long(CLI_CODCF);
    }
  }

  return 0;
}

void TImporta_fatven_app::put_rdoc_descr(TRiga_documento& rdoc, const TString& descr) const
{
  TParagraph_string para(descr, 50);
  rdoc.put(RDOC_DESCR, para.get(0));
  if (para.items() > 1)
  {
    TString s(256);
    for (const char* line = para.get(); line != NULL; line = para.get())
      s << '\n' << line;
    rdoc.put(RDOC_DESCLUNGA, true);
    rdoc.put(RDOC_DESCEST, s);
  }
}

bool TImporta_fatven_app::update_cfban(long codcf, const TVB_recset& s, int idx_abi) const
{
  const TString8 abi = togli_apici(s, idx_abi);
  const TString8 cab = togli_apici(s, idx_abi+1);
  if (codcf <= 0 || abi.blank() || cab.blank())
    return false;

  TLocalisamfile cfban(LF_CFBAN);
  cfban.put(CFBAN_TIPOCF, 'C');
  cfban.put(CFBAN_CODCF, codcf);
  cfban.put(CFBAN_TIPOBAN, idx_abi == 20 ? 'V' : 'N');
  cfban.put(CFBAN_NRIGA, 1);
  cfban.put(CFBAN_ABI, abi);
  cfban.put(CFBAN_CAB, cab);

  return cfban.rewrite_write() == NOERR;
}


//TRANSFER: metodo che effettivamente fa l'elaborazione del file di input, generando i vari documenti
//pronti per essere contabilizzati
bool TImporta_fatven_app::transfer(const TFilename& file)
{
  TLocalisamfile clifo(LF_CLIFO);
 
  const TString4 codnum = "F01"; //Da analisi
  const TString4 tpdoc = "F01";  //Da analisi

  TVB_recset s(file, ',');
  TLog_report log;
  TString msg;

  TProgress_monitor pi(s.items(), TR("Importazione fatture in corso ..."));

  long ndoc_old;

  s.move_first();
  //campi documento
  const long ndoc = ndoc_old = togli_apici_numero(s, 0); //ndoc
  const TDate datadoc = togli_apici(s,1);                //datadoc  
  const int anno = datadoc.year();                       //anno documento
  
  TDocumento doctmp('D', anno, codnum, ndoc_old);
  if (doctmp.physical_rows() > 0)
  {
#ifdef DBG
    if (!yesno_box(TR("I documenti che si sta cercando di importare esistono gi�.\nSi desidera proseguire ugualmente?")))
      return false;
#else
    return warning_box(TR("I documenti che si sta cercando di importare esistono gi�."));
#endif
  }

  for (bool ok = s.move_first(); ok; ok = s.move_next())
  {
    if (!pi.add_status()) 
      break;

    //leggo il contenuto del tracciato record

    //campi documento
    const long ndoc = togli_apici_numero(s, 0);  //ndoc
    if (ndoc <= 0)
      break;

    const TDate datadoc = togli_apici(s, 1);     //datadoc  
    const int anno = datadoc.year();            //anno documento
    
    //correggo l'imponibile dell'ultima riga del documento precedente per far tornare i conti
    if (ndoc != ndoc_old)
    {
      //carico il documento
      TDocumento doc('D', anno, codnum, ndoc_old);

      s.move_prev();
      real tot_doc = togli_apici(s,18);
      real tot_imp = doc.get_real("TOTVALORE");

      //se � necessario, faccio la modifica sull'ultima riga
      if (tot_imp != tot_doc)
      {
        //calcolo la differenza
        real diff = tot_doc - tot_imp;
        
        //estraggo l'imponibile dell'ultima riga        
        TRiga_documento& rdoc = doc[doc.rows()];
        real imp = rdoc.get_real(RDOC_PREZZO);

        //calcolo l'imponibile esatto e lo inserisco nella riga documento
        imp += diff;
        rdoc.put(RDOC_PREZZO, imp);
        doc.write();
      }
      //passo al nuovo documento
      ndoc_old = ndoc;
      s.move_next();
    }

    //campi articolo 1
    const TString descr1 = togli_apici_descr(s,2);        //descrizione articolo 1
    const TString80 art1 = togli_apici(s,3);              //articolo 1
    const real imp1 = togli_apici(s,4);                   //imponibile articolo 1
    //campi articolo 2
    const TString descr2 = togli_apici_descr(s,5);        //descrizione articolo 2
    const real imp2 = togli_apici(s,6);                   //imponibile articolo 2
    //campi articolo 3
    const TString descr3 = togli_apici_descr(s,7);        //articolo 3
    const real impives = togli_apici(s,8);                //imponibile iva esente
    //prendo codiva da anamag
    const TRectype& anamag = cache().get(LF_ANAMAG,art1);
    const TString16 codiva = anamag.get(ANAMAG_CODIVA);

    //partita iva, mi serve per sapere se un cliente esiste gi� in clifo
    const TString16 paiv = togli_apici(s,9);              //partita iva
    const TString80 ragsoc = togli_apici(s,10);           //ragione sociale
    
    //cerco gli altri dati di interesse
    long codcf = find_cliente(clifo, paiv, ragsoc);
    if (codcf <= 0)
    {
      //campi cliente (da utilizzare se non esiste gi�)
      const TString80 ind    = togli_apici(s,11);         //indirizzo
      const TString4 nciv    = togli_apici_numero(s,12);  //numero civico
      const TString8 cap     = togli_apici(s,13);         //CAP
      const TString80 comune = togli_apici(s,14);         //comune
      const TString80 loc    = togli_apici(s,15);         //localit�
      // const TString4 prov = togli_apici(s,16);         //provincia
      const TString& codcom = cap2comune(cap, comune);    //codice comune

      //calcolo il prossimo codice cliente libero
      codcf = 1L ;  
      clifo.setkey(1);
      if (!clifo.empty())
      {
        clifo.zero();
        clifo.put(CLI_TIPOCF, 'F');
        if (clifo.read(_isgteq) == NOERR)
          clifo.prev();
		    else
			    clifo.last();

        if (clifo.get_char(CLI_TIPOCF) == 'C')
          codcf += clifo.get_long(CLI_CODCF);
      }

      msg.cut(0) << TR("Inserimento cliente ") << codcf << ' ' << ragsoc;
      log.log(0, msg);
      if (paiv.blank())
        log.log(2, TR("Cliente privo di Partita IVA e Codice Fiscale"));
      //inserisco i dati di interesse
      clifo.zero();
      clifo.put(CLI_TIPOCF, 'C');
      clifo.put(CLI_CODCF, codcf);
      clifo.put(CLI_RAGSOC, ragsoc);
      if (paiv.len() == 16)
        clifo.put(CLI_COFI, paiv);
      else
        clifo.put(CLI_PAIV, paiv);
      clifo.put(CLI_INDCF, ind);
      clifo.put(CLI_CIVCF, nciv);
      clifo.put(CLI_CAPCF, cap);
      clifo.put(CLI_COMCF, codcom);
      clifo.put(CLI_LOCCF, loc);
      clifo.put(CLI_CODABI, togli_apici(s, 20));
      clifo.put(CLI_CODCAB, togli_apici(s, 21));

      const int err = clifo.write();
      if (err != NOERR)
      {
        msg.cut(0) << TR("Impossibile inserire il cliente ") << codcf 
                   << TR(" : errore ") << err;
        log.log(2, msg);
      }
    }

    TDocumento doc('D', anno, codnum, ndoc);
    const bool is_new = doc.physical_rows() == 0;
    doc.put(DOC_TIPODOC, tpdoc);
    doc.put(DOC_DATADOC, datadoc);
    doc.put(DOC_TIPOCF, 'C');
    doc.put(DOC_CODCF, codcf);

    doc.put(DOC_CODCMS,  togli_apici(s, 17));                
    doc.put(DOC_CODABIA, togli_apici(s, 20));
    doc.put(DOC_CODCABA, togli_apici(s, 21));
    doc.put(DOC_CODABIP, togli_apici(s, 22));
    doc.put(DOC_CODCABP, togli_apici(s, 23));
    doc.put(DOC_CODPAG,  togli_apici(s, 24));

    if (!imp1.is_zero())
    {      
      TRiga_documento& rdoc = doc.new_row("01");
      put_rdoc_descr(rdoc, descr1);
      rdoc.put(RDOC_PREZZO, imp1);
      rdoc.put(RDOC_QTA, 1);
      rdoc.put(RDOC_CODART, art1);
      rdoc.put(RDOC_CODARTMAG, art1);
      rdoc.put(RDOC_CHECKED, "X");
      rdoc.put(RDOC_CODIVA, codiva);
    }
      
    if (!imp2.is_zero())
    {
      TRiga_documento& rdoc = doc.new_row("01");

      put_rdoc_descr(rdoc, descr2);
      rdoc.put(RDOC_PREZZO, imp2);
      rdoc.put(RDOC_QTA, 1);
      rdoc.put(RDOC_CODART, art1);
      rdoc.put(RDOC_CODARTMAG, art1);
      rdoc.put(RDOC_CHECKED, "X");
      rdoc.put(RDOC_CODIVA, codiva);
    }

    if (!impives.is_zero())
    {
      TRiga_documento& rdoc = doc.new_row("01");      
      put_rdoc_descr(rdoc, descr3);
      rdoc.put(RDOC_PREZZO, impives);
      rdoc.put(RDOC_QTA, 1);     
      rdoc.put(RDOC_CHECKED, "X");
      rdoc.put(RDOC_CODIVA, codiva); //??????????????????????????????????
    }      
 
    int err = doc.write();
    if (err == NOERR)
    {
      if (is_new)
      {
        msg.cut(0) << TR("Inserito documento ") << ndoc;
        log.log(0, msg);
      }

      update_cfban(codcf, s, 20);
      update_cfban(codcf, s, 22);
    }
    else
    {
      msg.cut(0);
      if (is_new)
        msg << TR("Impossibile creare");
      else
       msg << TR("Impossibile aggiornare");
      msg << TR(" il documento ") << ndoc << TR(" : errore ") << err;
      log.log(2, msg);
    }
  }

  log.preview();

  return true;
}

void TImporta_fatven_app::main_loop()
{
  TImporta_fatven_msk msk;
  if (msk.run() == K_ENTER)
  {		
    //genero il nome del file da caricare
    TFilename name = msk.get(F_PATH);
    name.add(msk.get(F_NAME));
    if (name.exist())
      transfer(name);		
    else
      cantread_box(name);
  }   
}

int ps0713400 (int argc, char* argv[])
{
  TImporta_fatven_app main_app;
  main_app.run(argc, argv, TR("Importazione Fatture"));
  return true;
}