#include <automask.h>
#include <progind.h>
#include <relation.h>
#include <viswin.h>
#include <browfile.h>
#include <urldefid.h>

#include "baeur.h"
#include "baeura0.h"

#include "../cg/cg2103.h"
#include "../cg/cglib01.h"

#include "mov.h"
#include "partite.h"
#include "rmov.h"
#include "rmoviva.h"
#include "saldi.h"
#include "scadenze.h"

class TPirogano_mask : public TAutomask
{ 
  TViswin* _log_win;

protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  
public:
  void convert_movs(long fr, long to);
  TViswin& log_win() { return *_log_win; }

  TPirogano_mask();
};

bool TPirogano_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())
  {
  case DLG_PRINT:
    if (e == fe_button)
    {   
      _log_win->text().print();
      return FALSE; // Don't close
    }
    break;
  default:
    break;  
  }

  return TRUE;
}

TPirogano_mask::TPirogano_mask() : TAutomask("baeura0") 
{ 
  TBrowsefile_field& bf = (TBrowsefile_field&)field(F_LOG);
  _log_win = &bf.vis_win();                                
}

class TPirogano_app : public TEuro_app
{
  TPirogano_mask* _msk;
 
protected:
  virtual void main_loop();

public:
  void log_msg(TString& str);
  void log_war(TString& str);
  void log_err(TString& str);

  void scadenze_handler(TRectype& rec, const TRectype& part, real& totrate);
  void convert_scad(const TRectype& part);
  bool partite_handler(TRectype& rec);
  void convert_part(long num_reg);

  void update_saldo(const TRectype& rmov, int segno);
  void save_row(TEuroisamfile& rmov);
  void convert_rmovs(long num_reg, long num_rege);
  void convert_movs(long fr, long to);
};

void TPirogano_app::log_msg(TString& str)
{ 
  str.insert("- ");
  _msk->log_win().add_line(str);
}

void TPirogano_app::log_war(TString& str)
{ 
  str.insert("$[b,w]! ");
  _msk->log_win().add_line(str);
}

void TPirogano_app::log_err(TString& str)
{ 
  str.insert("$[r,w]* ");
  _msk->log_win().add_line(str);
}

void TPirogano_app::update_saldo(const TRectype& rmov, int segno)
{
  // File saldi in euro
  TEuroisamfile saldi(LF_SALDI, TRUE);
  TRectype& curr = saldi.curr();

  TBill zio; zio.get(rmov);
  curr.zero();
  curr.put(SLD_ANNOES, rmov.get(RMV_ANNOES));
  curr.put(SLD_GRUPPO, zio.gruppo());
  curr.put(SLD_CONTO, zio.conto());
  curr.put(SLD_SOTTOCONTO, zio.sottoconto());
  curr.put(SLD_FLSCA, "");
  
  const bool found = saldi.read(_isequal, _lock) == NOERR;
  if (!found)
  {
    curr.zero();
    curr.put(SLD_ANNOES, rmov.get(RMV_ANNOES));
    curr.put(SLD_GRUPPO, zio.gruppo());
    curr.put(SLD_CONTO, zio.conto());
    curr.put(SLD_SOTTOCONTO, zio.sottoconto());
    curr.put(SLD_FLSCA, "");
  }
  
  const TImporto importo(rmov.get_char(RMV_SEZIONE), rmov.get_real(RMV_IMPORTO));
  const char* field = importo.sezione() == 'D' ? SLD_PDARE : SLD_PAVERE;
  real saldo = curr.get(field);
  if (segno < 0)
    saldo -= importo.valore();
  else
    saldo += importo.valore();
  curr.put(field, saldo);
  
  const int err = found ? saldi.rewrite() : saldi.write();
  if (err != NOERR)
  {
    TString str;
    str << "Errore " << err << " durante l'aggiornamento dei saldi";
    log_err(str);
  }
}

void TPirogano_app::save_row(TEuroisamfile& rmov)
{
  const TRectype newrow = rmov.curr();
  TRectype oldrow(LF_RMOV);
  const bool found = rmov.read() == NOERR;
  if (found)
    oldrow = rmov.curr();
  rmov.curr() = newrow;
  const int err = found ? rmov.rewrite() : rmov.write();
  if (err != NOERR)  
  {    
    TString str;
    str << "Errore " << err << " durante la scrittura della riga " << rmov.get(RMV_NUMRIG);
    log_err(str);
  }
  else
  {
    if (found)
      update_saldo(oldrow, -1);  
    update_saldo(newrow, +1);  
  }
}

void TPirogano_app::convert_rmovs(long numreg, long numrege)
{
  // File righe movimento in euro
  TEuroisamfile fileur(LF_RMOV, TRUE);
  TRectype& receur = fileur.curr();
  
  TRelation rel(LF_RMOV);
  TRectype& curr = rel.curr();
  curr.put(MOV_NUMREG, numreg);
  TCursor cur(&rel, "", 1, &curr, &curr);
  const long items = cur.items();
  cur.freeze();
  
  TImporto saldo;
  int last_rowe = 0;
  
  for (cur = 0L; cur.pos() < items; ++cur)
  {     
    receur = curr;
    convert_import(receur, RMV_IMPORTO);
    saldo += TImporto(receur.get_char(RMV_SEZIONE), receur.get_real(RMV_IMPORTO));

    last_rowe = receur.get_int(RMV_NUMRIG);
    receur.put(RMV_NUMREG, numrege);
    save_row(fileur);
  }
  
  if (!saldo.is_zero())
  {  
    receur.zero();
    receur.put(RMV_NUMREG, numrege);
    receur.put(RMV_NUMRIG, ++last_rowe);
      
    TBill billy; load_round_bill(billy);
    billy.put(receur, FALSE);
      
    saldo.swap_section();
    saldo.normalize();
    receur.put(RMV_SEZIONE, saldo.sezione());
    receur.put(RMV_IMPORTO, saldo.valore());

    save_row(fileur);
  }
} 

void TPirogano_app::scadenze_handler(TRectype& rec, const TRectype& parte, real& totrate)
{ 
  convert_import(rec, SCAD_IMPORTO);

  if (!rec.get_real(SCAD_IMPORTOVAL).is_zero())
  {
    const TString& codval = parte.get(PART_CODVAL);
    if (codval.empty()) 
      rec.zero(SCAD_IMPORTOVAL);
  }
    
  const int nrata = rec.get_int(SCAD_NRATA);
  if (nrata == 1)
    totrate = ZERO;
  totrate += rec.get_real(SCAD_IMPORTO);
  
  // I problemi di arrotondamento dovrei averli solo con tante rate
  if (nrata > 1)
  {
    TLocalisamfile scad(LF_SCADENZE);
    scad.curr() = rec;
    scad.curr().put(SCAD_NRATA, nrata+1);
    if (scad.read() != NOERR)   // Sono l'ultima rata
    {
      const real toteur = parte.get(PART_IMPTOTDOC); 
      const real diff = toteur - totrate; 
      if (diff != ZERO)
      {
        real rata = rec.get(SCAD_IMPORTO);
        rata += diff;
        rec.put(SCAD_IMPORTO, rata);
      }
    }
  }  
}

void TPirogano_app::convert_scad(const TRectype& part)
{
  // File destinazione in euro
  TEuroisamfile fileur(LF_SCADENZE, TRUE);
  TRectype& receur = fileur.curr();

  TRelation rel(LF_SCADENZE);
  TRectype& curr = rel.curr();
  curr.put(SCAD_TIPOCF,     part.get(PART_TIPOCF));
  curr.put(SCAD_GRUPPO,     part.get(PART_GRUPPO));
  curr.put(SCAD_CONTO,      part.get(PART_CONTO));
  curr.put(SCAD_SOTTOCONTO, part.get(PART_SOTTOCONTO));
  curr.put(SCAD_ANNO,       part.get(PART_ANNO));
  curr.put(SCAD_NUMPART,    part.get(PART_NUMPART));
  curr.put(SCAD_NRIGA,      part.get(PART_NRIGA));

  TCursor cur(&rel, "", 1, &curr, &curr);  // Seleziona solo le rate interessate

  const long items = cur.items();
  cur.freeze();
  real totrate;
  for (cur = 0L; cur.pos() < items; ++cur)
  {
    receur = curr;
    scadenze_handler(receur, part, totrate);
    int err = fileur.write();
    if (err != NOERR)        
      err = fileur.rewrite();
    if (err != NOERR)
    {    
      TString str;
      str << "Errore " << err << " durante la scrittura della rata " << receur.get(SCAD_NRIGA);
      log_err(str);
    }
  }
}

bool TPirogano_app::partite_handler(TRectype& rec)
{
  if (rec.get_bool(PART_CHIUSA) || rec.get_int(PART_NRIGA) == 9999)
    return FALSE;
                                                                          
  zero_import(rec, PART_NREG); // Creo solo partite extra-contabili
  convert_import(rec, "IMPTOTDOC|IMPORTO|IMPOSTA|SPESE|RITENUTE|DIFFCAM");
    
  const TString16 codval = rec.get(PART_CODVAL);
  if (::is_firm_value(codval))
  {
    convert_import(rec, PART_ABBUONI);
    zero_import(rec, "CODVAL|IMPORTOVAL|DIFFCAM");
  } else
  if (::is_euro_value(codval))
  {
    zero_import(rec, "CODVAL|IMPORTOVAL|DIFFCAM");
  } else
  if (::is_true_value(codval))
  {
    const real impval = rec.get(PART_IMPORTOVAL);
    if (impval != ZERO)
    {
      const real impeur = rec.get(PART_IMPORTO);
      const real old_cambio = rec.get(PART_CAMBIO);
      real new_cambio = impval / impeur;
      new_cambio.round(5);
      if (abs(old_cambio - new_cambio) > 0.001) // Non era gi� contro euro
        rec.put(PART_CAMBIO, new_cambio);
    }
  }
  
  if (rec.get_int(PART_TIPOMOV) > 1)            
  {
    // Riempe il campo totale documento per i pagamenti (In contabilit� viene lasciato vuoto)
    rec.put(PART_IMPTOTDOC, rec.get(PART_IMPORTO));
  }
  
  rec.put(PART_INVIATA, "X");
                                   
  return TRUE;  
}

void TPirogano_app::convert_part(long num_reg)
{
  // File destinazione in euro
  TEuroisamfile fileur(LF_PARTITE, TRUE);
  TRectype& receur = fileur.curr();

  TRelation rel(LF_PARTITE);
  TRectype& curr = rel.curr();
  curr.put(PART_NREG, num_reg);
  TCursor cur(&rel, "", 2, &curr, &curr);  // Seleziona solo le partite interessate
  
  const long items = cur.items();
  cur.freeze();
  TString str;    
  
  bool one_saved = FALSE;
  if (items > 0)
  {
    str << "Conversione della partita extracontabile " << curr.get(PART_ANNO);
    str << '/' << curr.get(PART_NUMPART);
    log_msg(str);   
    for (cur = 0L; cur.pos() < items; ++cur)
    {
      receur = curr;
      if (partite_handler(receur))
      {
        int err = fileur.write();
        if (err != NOERR)        
          err = fileur.rewrite();
        if (err != NOERR)
        {
          str.cut(0) << "Errore " << err << " durante la scrittura della riga " << receur.get(PART_NRIGA);
          log_err(str);
        }
        else          
        {
          convert_scad(receur);
          one_saved = TRUE;
        }
      }
    }
  }
  if (!one_saved)
  {
    str = "Non sono state rilevate scadenze aperte";
    log_war(str);
  }
}

void TPirogano_app::convert_movs(long fr, long to)
{ 
  _msk->log_win().destroy_lines();

  // File destinazione in euro
  TEuroisamfile fileur(LF_MOV, TRUE);
  TRectype& receur = fileur.curr();
  
  long next_rege = 1;
  if (fileur.last() == NOERR)
    next_rege = receur.get_long(MOV_NUMREG)+1;
  
  TRelation rel(LF_MOV);
  TRectype& curr = rel.curr();             
  
  TRectype fr_mov(curr); if (fr > 0) fr_mov.put(MOV_NUMREG, fr);
  TRectype to_mov(curr); if (to > 0) to_mov.put(MOV_NUMREG, to);
  TCursor cur(&rel, "", 1, &fr_mov, &to_mov);
  
  TString str;
  str << "Conversione " << rel.lfile().description() << " ...";
    
  const long items = cur.items();
  cur.freeze();
  TProgind pi(items, str, FALSE, TRUE);
  for (cur = 0L; cur.pos() < items; ++cur)
  {     
    pi.addstatus(1);

    const long num_reg = curr.get_long(MOV_NUMREG);
    const TDate datareg = curr.get(MOV_DATAREG);   
    const int yearreg = datareg.year();
    const long clifo = curr.get_long(MOV_CODCF);

    const TString8 caus = curr.get(MOV_CODCAUS);
    TipoIVA iva = nessuna_iva;
    int tipomov = 0;
    if (caus.not_empty())
    {
      TCausale causale(caus, yearreg);
      iva = causale.iva();
      tipomov = causale.tipomov();
    }
    
    bool converted = FALSE;
    if (yearreg == 2002 && iva == nessuna_iva && tipomov == 0)
    {
      receur = curr;
      convert_import(receur, MOV_TOTDOC);  // Forse inutile
      
      int err = 0;
      long num_rege = curr.get_long("TNUMREG");
      if (num_rege <= 0)   
      {
        num_rege = next_rege++;
        curr.put("TNUMREG", num_rege);
          rel.rewrite();
      }
      receur.put(MOV_NUMREG, num_rege);
      
      str.cut(0) << "Conversione del movimento " << num_reg << " -> " << num_rege;
      log_msg(str);
      
      err = fileur.write();
      if (err != NOERR)
        err = fileur.rewrite();
        
      if (err != NOERR)
      {  
        str.cut(0) << "Errore " << err << " durante la scrittura della testata";
        log_err(str);
      }
      convert_rmovs(num_reg, num_rege);
      converted = TRUE;
    }  
    if (yearreg == 2001 && iva != nessuna_iva && tipomov == 1)
    {
      str.cut(0) << "Elaborazione della partita del movimento " << num_reg;
      log_msg(str);
      convert_part(num_reg);
      converted = TRUE;
    }
    
    if (!converted)
    {
      str.cut(0) << "Ignorato movimento "  << num_reg << " del " << datareg;
      if (caus.not_empty()) str << " con causale " << caus;
      log_war(str);
      continue;
    }
  }
  
  _msk->log_win().goto_end();
}

void TPirogano_app::main_loop()
{
  open_files(LF_TABCOM, LF_TAB, LF_MOV, LF_RMOV, LF_CAUSALI, LF_SALDI, LF_PARTITE, LF_SCADENZE, 0);

  TFilename dati, datie;
  get_aree_dati(dati, datie);

  _msk = new TPirogano_mask;
  TMask& m = *_msk;
  m.set(F_DATI, dati);
  m.set(F_DATIE, datie);
  
  const long firm = get_firm();
  TString8 ditta; 
  ditta.format("%05ldA", firm);
  TFilename inie = datie;
  inie.add(ditta);
  inie.add("prassid.ini");
  
  KEY k = K_ENTER;
  while (k == K_ENTER)
  {
    if (inie.exist())
    {
      TConfig config(inie, "Euro");
      m.set(F_ADOZIONE, config.get("Adozione"));
      m.set(F_LAST_DATE, config.get("InvDate"));
      m.set(F_LAST_FROM, config.get("InvFirst"));
      m.set(F_LAST_TO,   config.get("InvLast"));
    }
    else
    {
      error_box("Non esiste la ditta %ld nell'area dati in Euro %s", firm, (const char*)datie);
      m.disable(DLG_OK);
    }    
    
    k = m.run();
    if (k == K_ENTER)
    {
      const long fr_mov = m.get_long(F_MOV_FROM); 
      const long to_mov = m.get_long(F_MOV_TO); 

      convert_movs(fr_mov, to_mov);
      
      TConfig config(inie, "Euro");
      config.set("InvDate", TDate(TODAY));
      config.set("InvFirst", fr_mov);
      config.set("InvLast", to_mov);
    }
  }
  
  delete _msk;
  _msk = NULL;
}

///////////////////////////////////////////////////////////
// main
///////////////////////////////////////////////////////////

int baeur0A(int argc, char* argv[])
{  
  TPirogano_app app;
  app.run(argc, argv, "Trasferimento movimenti 2002");
  return 0;
}