#include <applicat.h>
#include <automask.h>
#include <browfile.h>
#include <defmask.h>
#include <relation.h>
#include <viswin.h>

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

#include "sc2.h"
#include "sc2500.h"

#include <clifo.h>
#include <nditte.h>
#include <partite.h>
#include <pconti.h>
#include <rmov.h>
#include <rcausali.h>

///////////////////////////////////////////////////////////
// Maschera principale
///////////////////////////////////////////////////////////

class TConfronta_mask : public TAutomask
{   
  bool _running;
  int _last_perc;
  
protected:
  virtual bool on_field_event(TOperable_field& f, TField_event e, long jolly);

public:   
  int esercizio_corrente() const;
  
  TImporto importo_riga(const TRectype& riga) const;
  real calcola_saldo_partite(char tipoc, int g, int c, long s, bool is_default = FALSE) const;
  
  bool add_saldo(int g, int c, long s, const TString& d, real salc, real salp);
  void show_progress(long pos, long tot);
  void fill_browse();

  TConfronta_mask();
  virtual ~TConfronta_mask() { }
};

int TConfronta_mask::esercizio_corrente() const
{
  TEsercizi_contabili esc;
  TDate oggi(TODAY);
  return esc.date2esc(oggi);
}

bool TConfronta_mask::add_saldo(int g, int c, long s, const TString& d, real salc, real salp)     //+
{           
  bool ok = !(salc.is_zero() && salp.is_zero()) && (salc != salp || get_bool(F_BILANCIATI));
  if (ok)
  {
    char sezs = 'D';
    real sals = salc - salp;
    if (sals.sign() < 0)
    {
      sals = -sals;
      sezs = 'A';
    }
    char sezc = 'D';
    if (salc.sign() < 0)
    {
      salc = -salc;
      sezc = 'A';
    }
    char sezp = 'D';
    if (salp.sign() < 0)
    {
      salp = -salp;
      sezp = 'A';
    }
    TString256 str;
    TString80 i0, i1, i2, i3; 
    const TCurrency impc(salc), impp(salp), imps(sals);
    i0 = d.left(30);
    i1.format("%17s %c", impc.string(TRUE), sezc);
    i2.format("%17s %c", impp.string(TRUE), sezp);
    i3.format("%17s %c", imps.string(TRUE), sezs);
    str.format("%3d %3d %6ld %-30s %s %s %s", g, c, s, (const char*)i0, (const char*)i1, (const char*)i2, (const char*)i3); //+
    
    TBrowsefile_field& b = (TBrowsefile_field&)field(F_PREVIEW);
    b.add_line(str);
  }
  return ok;
}


TImporto TConfronta_mask::importo_riga(const TRectype& riga) const
{
  TImporto i(riga.get_char(PART_SEZ), riga.get_real(PART_IMPORTO));

  if (riga.get_int(PART_TIPOMOV) > 1) // Non e' una fattura
  {               
    const TString16 codval = riga.get(PART_CODVAL);
    const bool in_valuta = is_true_value(codval);  // Determina se in valuta

    real abb = riga.get_real(PART_ABBUONI);
    if (in_valuta)
    {
      TCurrency abbval(abb, codval, riga.get_real(PART_CAMBIO)); 
      abbval.change_to_firm_val();
      abb = abbval.get_num();
    }  
      
    TImporto abbuoni(riga.get_char(PART_SEZABB), abb);  
    i += abbuoni;
      
    if (in_valuta)
    {
      const TImporto diffcam(riga.get_char(PART_SEZDIFCAM), riga.get_real(PART_DIFFCAM));
      i += diffcam;
    }  
    else
    {
      i.valore() += riga.get_real(PART_RITENUTE);

      const real ritsoc = riga.get_real(PART_RITSOC);
      if (!ritsoc.is_zero())
      {
        TString16 key; key << riga.get(PART_CODCAUS) << "|14";  // Riga ritenute sociali
        const char sezcaus = cache().get(LF_RCAUSALI, key, RCA_SEZIONE)[0];
        const char sezrs = sezcaus > ' ' ? (sezcaus == 'D' ? 'A' : 'D') : riga.get_char(PART_SEZ);
        i += TImporto(sezrs, ritsoc);
      }
    }
  }
  return i;
}

real TConfronta_mask::calcola_saldo_partite(char tipoc, int g, int c, long s, bool is_default) const
{ 
  TRelation rel(LF_PARTITE);
  TString filter = "(NRIGA!=9999)";
  TRectype region(LF_PARTITE);
  region.put(PART_TIPOCF, tipoc);
  if (tipoc > ' ')
  {
    // Accetta anche GRUPPOCL nullo per ora
    filter << "&&((GRUPPOCL=0)||((GRUPPOCL=" << g << ")&&(CONTOCL=" << c << ")))";
  }
  else
  {
    region.put(PART_GRUPPO, g);
    region.put(PART_CONTO, c);
  }
  region.put(PART_SOTTOCONTO, s);
  
  TCursor part(&rel, filter, 1, &region, &region);
  const TRecnotype items = part.items();
  part.freeze();
  
  real saldo;
  const TRectype& rec = part.curr();
  for (part = 0; part.pos() < items; ++part)
  {
    if (tipoc > ' ' && rec.get_int(PART_GRUPPOCL) == 0)
    {
      int gprovv = 0, cprovv = 0;   // Conto cliente provvisorio
      
      // Cerco di determinare il conto dalla riga di movimento
      const long numreg = rec.get_long(PART_NREG);
      const int numrig = rec.get_int(PART_NUMRIG);
      if (numreg > 0 && numrig > 0)
      {                                                  
        TString16 key; key.format("%ld|%d", numreg, numrig);
        const TRectype& rmov = cache().get(LF_RMOV, key);
        if (!rmov.empty())  // Ho trovato la riga contabile corrispondente
        {
          gprovv = rmov.get_int(RMV_GRUPPO);
          cprovv = rmov.get_int(RMV_CONTO);
        }
      }
      if (gprovv == 0 && is_default)  // Non ho trovato il movimento contabile
      {
        gprovv = g;
        cprovv = c;
      }
      if (gprovv != g || cprovv != c) // Scarto la riga in quanto non corrispondente
        continue;
    }
    
    const TImporto imp = importo_riga(rec);
    if (imp.sezione() == 'D')
      saldo += imp.valore();
    else
      saldo -= imp.valore();
  }
  return saldo;
}

void TConfronta_mask::show_progress(long pos, long tot)
{
  const int perc = int((pos+1) * 100L / tot);
  if (perc != _last_perc)
  {
    TString80 str; str.format(FR("%d%% completato"), perc);
    xvtil_statbar_set(str);
    _last_perc = perc;
    do_events();
  }
}

void TConfronta_mask::fill_browse()
{                   
  _running = true;
  TWait_cursor hourglass;
  TBrowsefile_field& b = (TBrowsefile_field&)field(F_PREVIEW);
  TViswin& w = b.vis_win();
  w.destroy_lines();
//crea la nuova intestazione
  TString intestazione;
	const long firm = main_app().get_firm();
  const TString & ragsoc = cache().get(LF_NDITTE, firm, NDT_RAGSOC);

  intestazione << FR("@bDitta ") << firm;
  intestazione << " " << ragsoc; 
  intestazione.rpad(97);
  TDate oggi(TODAY);
  intestazione << oggi;
     
  b.add_line(intestazione);
  b.add_line(FR("@bSTAMPA CONTROLLO SALDI"));
  b.add_line("@b_________________________________________________________________________________________________________");
  b.add_line("");
  b.add_line(FR("@bGrp Cnt Sottoc Descrizione                        Saldo Contabile       Saldo Partite           Sbilancio"));
  b.add_line("@b_________________________________________________________________________________________________________");
  b.add_line("");

  TToken_string str;
  
  TSaldo sld;
  const int annoes = esercizio_corrente();
  const char tipoc = get(F_TIPOC)[0];
  
  xvtil_statbar_set(TR("Inizializzazione..."));
  _last_perc = -1;
  do_events();

  if (tipoc <= ' ')
  {
    TRelation rel(LF_PCON); 
    TRectype da_con(LF_PCON), a_con(LF_PCON);
    da_con.put(PCN_GRUPPO, get(F_GRUPPO));
    da_con.put(PCN_CONTO, get(F_CONTO));
    da_con.put(PCN_SOTTOCONTO, get(F_SOTTOCONTO));
    a_con.put(PCN_GRUPPO, get(F_AGRUPPO));
    a_con.put(PCN_CONTO, get(F_ACONTO));
    a_con.put(PCN_SOTTOCONTO, get(F_ASOTTOCONTO));
    TCursor piano(&rel, "SOTTOCONTO!=\"\"", 1, &da_con, &a_con);
    const TRecnotype items = piano.items();
    piano.freeze();
    const TRectype& rec = piano.curr();
    for (piano = 0; piano.pos() < items && _running; ++piano)
    { 
      show_progress(piano.pos(), items);
      const int g = rec.get_int(PCN_GRUPPO);
      const int c = rec.get_int(PCN_CONTO);
      const long s = rec.get_long(PCN_SOTTOCONTO);
      const TString d = piano.curr().get(PCN_DESCR); //+
      
      str.format("%d|%d", g, c);       
      const int indbil = cache().get(LF_PCON, str).get_int(PCN_INDBIL);
      sld.ultima_immissione_bilancio(annoes, g, c, s, indbil, 1);
      const real salc = sld.saldo();
      const real salp = calcola_saldo_partite(' ', g, c, s);
      add_saldo(g, c, s, d, salc, salp);   //+
    }
  }
  else
  {
    TString_array conti;
    if (get_int(F_CONTO) > 0)
    {
      str.cut(0) << get(F_GRUPPO) << '|' << get(F_CONTO);
      conti.add(str);
    }
    else
    {
      TRelation rel(LF_PCON);
      str.cut(0) << PCN_TMCF << "==\"" << tipoc << '\"';
      TCursor pcon(&rel, str);
      const TRecnotype conticf = pcon.items();    
      for (pcon = 0; pcon.pos() < conticf; ++pcon)
      {
        str = pcon.curr().get(PCN_GRUPPO);
        str << '|' << pcon.curr().get(PCN_CONTO);
        conti.add(str);
      }
    }
    for (int c = conti.last(); c >= 0; c--)
    {                                                
      TToken_string& k = conti.row(c);
      const TRectype& pcon = cache().get(LF_PCON, k);
      if (!pcon.empty())
        k.add(pcon.get(PCN_INDBIL));
    }

    TRelation rel(LF_CLIFO); 
    TRectype da_cli(LF_CLIFO), a_cli(LF_CLIFO);   
    da_cli.put(CLI_TIPOCF, tipoc);
    da_cli.put(CLI_CODCF, get(F_SOTTOCONTO));
    a_cli.put(CLI_TIPOCF, get(F_TIPOC));
    a_cli.put(CLI_CODCF, get(F_ASOTTOCONTO));
    TCursor clienti(&rel, "", 1, &da_cli, &a_cli);
    const TRecnotype items = clienti.items();
    clienti.freeze();
    
    for (clienti = 0; clienti.pos() < items && _running; ++clienti)
    {      
      show_progress(clienti.pos(), items);
      const int def_grp = clienti.curr().get_int(CLI_GRUPPO);
      const int def_cnt = clienti.curr().get_int(CLI_CONTO);
      int def_conto = 0;  // Per il momento assumiamo che il conto di default sia il primo
      for (int i = 0; i < conti.items() && _running; i++)
      {               
        str = conti.row(i);
        const int  g = str.get_int(0);
        const int  c = str.get_int(1);
        const long s = clienti.curr().get_long(CLI_CODCF);
        const TString d = clienti.curr().get(CLI_RAGSOC);    //+
        const int indbil = str.get_int(2);
        if (g == def_grp && c == def_cnt)  // Abbiamo trovato il vero conto di default
          def_conto = i;
        sld.ultima_immissione_bilancio(annoes, g, c, s, indbil, 1);
        const real salc = sld.saldo();
        const real salp = calcola_saldo_partite(tipoc, g, c, s, def_conto == i);
        add_saldo(g, c, s, d, salc, salp);     //+
      }
    }
  }
  w.goto_top();
  _running = false;
}

bool TConfronta_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{     
  switch (f.dlg())
  {       
  case DLG_ELABORA:
    if (e == fe_button && !_running)
    {                       
      // disabilito campi di selezione e bottone elabora
      disable(-4);
      field(DLG_PRINT).set_focus();                                      
      // sostituisco elabora con annulla
      hide(DLG_ELABORA); show(F_CANCEL);
      // elaborazione
      fill_browse(); 
      // sostituisco annulla con elabora
      hide(F_CANCEL); show(DLG_ELABORA);
      // abilito bottone stampa
      enable(-6);
    }  
    break;
  case F_CANCEL:
    if (e == fe_button)
      _running = false;
    break;    
  case DLG_PRINT:
    if (e == fe_button)
    {
      TBrowsefile_field& b = (TBrowsefile_field&)field(F_PREVIEW);
      TViswin& w = b.vis_win();
      TTextfile& f = w.text();
      f.print();
    }
    break;    
  case F_AZZERA:
    if (e == fe_button)
    {                             
      // azzero il campo risultato della stampa
      TBrowsefile_field& b = (TBrowsefile_field&)field(F_PREVIEW);
      TViswin& w = b.vis_win();
      w.destroy_lines();
      w.goto_top();
      // disabilito bottone stampa
      disable(-6);     
      // abilito campi di selezione e bottone elabora
      enable(-4);
    }
    break;  
  default:
    break;
  }
  return TRUE;
}

TConfronta_mask::TConfronta_mask()
               : TAutomask("sc2500"), _running(FALSE)
{
}

///////////////////////////////////////////////////////////
// Applicazione principale
///////////////////////////////////////////////////////////

class TConfronta_saldi : public TSkeleton_application
{
public:  
  virtual void main_loop();
};        

void TConfronta_saldi::main_loop()
{   
  open_files(LF_TAB, LF_TABCOM, LF_PCON, LF_CLIFO, LF_SALDI, 
             LF_RCAUSALI, LF_PARTITE, LF_RMOV, 0);
  TConfronta_mask m;
  while (m.run() != K_QUIT);
}

int sc2500(int argc, char** argv)     
{
  TConfronta_saldi app;
  app.run(argc, argv, TR("Stampa controllo saldi"));
  return 0;
}