/////////////////////////////////////////////////////////////////////////////
// cglib02.cpp 
// 
// Aggiornamento saldi
//
/////////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include <prefix.h>
#include <utility.h>

#include "cglib.h"

#include <saldi.h>

TConto* TTab_conti::add(const TBill& c, int anno)
{
  TString80 key;
  key.format("%4d%3d%3d%6ld", anno, c.gruppo(), c.conto(), c.sottoconto());
  TConto* tc = new TConto(c.gruppo(), c.conto(), c.sottoconto(), c.tipo());
  TAssoc_array::add(key, tc);
  return tc;
}

TConto* TTab_conti::find(const TBill& c, int anno)
{
  TString80 key;
  key.format("%4d%3d%3d%6ld", anno, c.gruppo(), c.conto(), c.sottoconto());
  TConto* tc = (TConto*)objptr(key);
  return tc;
}

void TTab_conti::remove(const TBill& c, int anno)
{
  TString80 key;
  key.format("%4d%3d%3d%6ld", anno, c.gruppo(), c.conto(), c.sottoconto());
  TAssoc_array::remove(key);
}

void TTab_conti::aggiorna_conto(const TBill& tcon, 
                                int anno_es, const TImporto& importo, bool movap,
                                bool provv, bool somma, bool movimentato)
{
  TConto* tc = find(tcon, anno_es);
  if (tc == NULL)
    tc = add(tcon, anno_es);

  const real i(somma ? importo.valore() : -importo.valore());

  if (movap)
  {
    if (importo.sezione() == 'D') 
      tc->saldo() += i;
    else 
      tc->saldo() -= i;
  }
  else
    if (provv)
    {
      if (importo.sezione() == 'D') 
        tc->darepro() += i;
      else 
        tc->averepro() += i;
    }
    else
    {
      if (importo.sezione() == 'D') 
        tc->dare() += i;
      else 
        tc->avere() += i;
    }

  // rimuovo dalla tabella il conto se dare e avere vanno a zero
  if (!movimentato)
    if (tc->dare().is_zero() && tc->avere().is_zero() &&
        tc->darepro().is_zero() && tc->averepro().is_zero() &&
        tc->saldo().is_zero()) 
      remove(*tc, anno_es);  
}

TSaldo_agg::TSaldo_agg() 
{
  _anno_es     = 0;
  _data_ulmov  = "";
  _num_ulmov   = 0l;
  _movap       = FALSE;
  _provv       = FALSE;
  _movimentato = FALSE;
  // reset();  // INUTILE pulizia dell'array dei conti
}

void TSaldo_agg::aggiorna(const TBill& tc, const TImporto& imp, bool somma)
{                     
  _tab_conti.aggiorna_conto(tc, _anno_es, imp, _movap, _provv, somma, _movimentato);
}

void TSaldo_agg::aggiorna(int gruppo, int conto, long sottoconto, const real& importo, char sezione, bool somma)
{
  const TImporto imp(sezione, importo);
  _tab_conti.aggiorna_conto(TBill(gruppo, conto, sottoconto), _anno_es, imp, _movap, _provv, somma, _movimentato);
}

void TSaldo_agg::reset()
{
  _tab_conti.destroy();
}

///////////////////////////////////////////////////////////////////////////////
// pulizia file saldi
// 
// Scorro il file saldi per l' anno year o per tutti gli anni se year = 0
// e azzero i progressivi.
// 
///////////////////////////////////////////////////////////////////////////////

void TSaldo_agg::clear_saldi(int year)
{
  TLocalisamfile saldi(LF_SALDI);

  set_anno_es(year);
  saldi.zero();
  if (anno_es() != 0)
    saldi.put(SLD_ANNOES, anno_es());

  TRectype last(saldi.curr());

  for (saldi.read(_isgteq, _lock);
       !saldi.eof() && saldi.curr() <= last;
       saldi.next(_lock))
  {
    saldi.put(SLD_FLAGSALINI, "D");
    saldi.zero(SLD_SALDO);
    saldi.zero(SLD_PDAREPRO);
    saldi.zero(SLD_PAVEREPRO);
    saldi.zero(SLD_PDARE);
    saldi.zero(SLD_PAVERE);
    saldi.zero(SLD_NUMULTMOV);
    saldi.zero(SLD_DATAULMOV);
    saldi.rewrite();
  }
  saldi.reread(_unlock);
}

///////////////////////////////////////////////////////////////////////////////
// Aggiornamento file saldi
// 
// Scorro la tabella dei conti interna _tab_conti.
// Per ogni conto cerco il record su saldi, se non c'e' lo creo.
// Se c'e' gia' lo aggiorno nel seguente modo:
// 
///////////////////////////////////////////////////////////////////////////////
void TSaldo_agg::registra()
{
  real si, r;
  char flag_salini;
  TDate   data_ulmov;
  long    num_ulmov;
  TLocalisamfile saldi(LF_SALDI);
  int conti = _tab_conti.items();

  _tab_conti.restart();
  for (int i = 0; i < conti; i++)
  {
    THash_object* hobj = _tab_conti.get_hashobj(); 
    TConto& tcon = (TConto &)hobj->obj();
    CHECK(tcon.ok(), "Tentavi di saldare un conto incompleto, eh?");
    
    saldi.zero();
    saldi.put(SLD_ANNOES, atoi(hobj->key().left(4)) );
    saldi.put(SLD_GRUPPO, tcon.gruppo());
    saldi.put(SLD_CONTO,  tcon.conto());
    saldi.put(SLD_SOTTOCONTO, tcon.sottoconto());
    
    bool update = TRUE;

    if (saldi.read(_isequal, _lock) != NOERR)
    {
      saldi.zero();
      saldi.put(SLD_ANNOES, atoi(hobj->key().left(4)));
      saldi.put(SLD_GRUPPO, tcon.gruppo());
      saldi.put(SLD_CONTO, tcon.conto());
      saldi.put(SLD_SOTTOCONTO, tcon.sottoconto());
      si = tcon.saldo();
      if (si < ZERO)
      { flag_salini = 'A'; si = -si; }
      else
        flag_salini = 'D';
      
      saldi.put(SLD_FLAGSALINI, flag_salini);
      saldi.put(SLD_SALDO, si);
      saldi.put(SLD_PDAREPRO, tcon.darepro());
      saldi.put(SLD_PAVEREPRO, tcon.averepro());
      saldi.put(SLD_PDARE, tcon.dare());

      saldi.put(SLD_PAVERE, tcon.avere());
      if (_num_ulmov != 0L) saldi.put(SLD_NUMULTMOV, _num_ulmov);
      if (_data_ulmov.ok()) saldi.put(SLD_DATAULMOV, _data_ulmov);
      update = saldi.write() == _isreinsert;
      if (update)
        saldi.read(_isequal, _lock);
    } 
    
    if (update)
    {
      num_ulmov  = saldi.get_long(SLD_NUMULTMOV);
      data_ulmov = saldi.get_date(SLD_DATAULMOV);

      if ((_num_ulmov != 0L) && (_num_ulmov > num_ulmov))
        saldi.put(SLD_NUMULTMOV, _num_ulmov);
      if ((_data_ulmov.ok()) && (_data_ulmov > data_ulmov))
        saldi.put(SLD_DATAULMOV, _data_ulmov);
      r = tcon.saldo();
      si = saldi.get_real(SLD_SALDO);
      flag_salini = saldi.get_char(SLD_FLAGSALINI);
      if (r != ZERO)
      {
        if (flag_salini == 'A') si = r - si;
        else si += r;
        if (si < ZERO)
        {
          flag_salini = 'A'; si = -si;
        }
        else
          flag_salini = 'D';
        saldi.put(SLD_FLAGSALINI, flag_salini);
        saldi.put(SLD_SALDO, si);
      }
      r = saldi.get_real(SLD_PDAREPRO);
      r += tcon.darepro();
      saldi.put(SLD_PDAREPRO,  r);
      r = saldi.get_real(SLD_PAVEREPRO);
      r += tcon.averepro(); 
      saldi.put(SLD_PAVEREPRO, r);
      r = saldi.get_real(SLD_PDARE);
      r += tcon.dare();
      saldi.put(SLD_PDARE,  r);
      r = saldi.get_real(SLD_PAVERE);
      r += tcon.avere(); 
      saldi.put(SLD_PAVERE, r);
      
      const int err = saldi.rewrite();
      if (err != NOERR)
      {
        yesnofatal_box("Errore %d nell'aggiornamento del saldo %d %d %ld", 
                       err, tcon.gruppo(), tcon.conto(), tcon.sottoconto());
      }  
    }
    
    TImporto sf(flag_salini, si);
    const TImporto dare('D', saldi.get_real(SLD_PDARE));
    const TImporto avere('A', saldi.get_real(SLD_PAVERE));
    sf += dare;
    sf += avere;
    sf.normalize(+1);              // Rendi sempre positivo
    tcon.saldo_finale() = sf;
  }
}


///////////////////////////////////////////////////////////
// Gestione Tabella esercizi
///////////////////////////////////////////////////////////

TEsercizio::TEsercizio(const TRectype& rec)
{                   
  _codice  = rec.get_int("CODTAB");
  _inizio  = rec.get("D0");
  _fine    = rec.get("D1");
  _scarico = rec.get("D2");
}

int TEsercizio::compare(const TSortable& s) const
{
  const TEsercizio& e = (const TEsercizio&)s;
  int c = 0;
  if (_inizio != e._inizio) 
    c = _inizio > e._inizio ? +1 : -1;
  return c;  
}

TEsercizi_contabili::TEsercizi_contabili() : _firm(0)
{ }

void TEsercizi_contabili::update()
{       
  _firm = prefix().get_codditta();
  
  destroy();
  TTable esc("ESC");
  for (int err = esc.first(); err == NOERR; err = esc.next())
  {
    TEsercizio* e = new TEsercizio(esc.curr());
    add(e);
  }              
  sort();
} 

void TEsercizi_contabili::check()
{
  if (_firm != prefix().get_codditta())
  {
#ifdef DBG   
    if (_firm != 0)
      error_box("Questo programma carinissimo usa gli esercizi, "
                "ma purtroppo non tiene conto del cambio ditta!");
#endif  
    update();
  }
}

int TEsercizi_contabili::date2index(const TDate& d)
{
  check();    
  for (int i = items()-1; i >= 0; i--)
  {     
    const TEsercizio& e = esc(i);
    if (d >= e.inizio() && d <= e.fine())
      break;
  }
  return i;
}

int TEsercizi_contabili::esc2index(int codice)
{
  check();    
  for (int i = items()-1; i >= 0; i--)
  {     
    const TEsercizio& e = esc(i);
    if (codice == e.codice())
      break;
  }
  return i;
}

int TEsercizi_contabili::date2esc(const TDate& d)
{
  const int i = date2index(d);
  return i >= 0 ? esc(i).codice() : 0;
}

int TEsercizi_contabili::first()
{
  check();
  return items() ? esc(0).codice() : 0;
}

int TEsercizi_contabili::last()
{
  check();
  return items() ? esc(items()-1).codice() : 0;
}

int TEsercizi_contabili::pred(int codice)
{
  const int i = esc2index(codice);
  return i > 0 ? esc(i-1).codice() : 0;
}

int TEsercizi_contabili::next(int anno)
{
  const int i = esc2index(anno);
  return i < items()-1 ? esc(i+1).codice() : 0;
}

bool TEsercizi_contabili::exist(int codice)
{
  const int i = esc2index(codice);
  return i >= 0;
}

const TEsercizio& TEsercizi_contabili::esercizio(int codice)
{
  const int i = esc2index(codice);
  return esc(i);
}




