// cglib01.cpp
// calcolo dei saldi

#include <config.h>
#include <xvtility.h>

#include <rmov.h>
#include <mov.h>
#include <saldi.h> 
#include <pconti.h> 
#include <causali.h> 
#include <clifo.h> 

#include "cglib.h"

///////////////////////////////////////////////////////////
// Causale
///////////////////////////////////////////////////////////

TCaus::TCaus(const char* cod) : _rec(LF_CAUSALI)
{
  read(cod);
}


// Legge le righe della causale attualmente selezionata sulla maschera
bool TCaus::read(const char* cod)
{ 
  bool ok = FALSE;
  if (cod && *cod)
  {
    TLocalisamfile caus(LF_CAUSALI);
    caus.setkey(1);
    caus.put(CAU_CODCAUS, cod);

    ok = caus.read() == NOERR;
    if (ok) 
      _rec = caus.curr();
    else
      _rec.zero();
  } 
  else
    _rec.zero();
       
  return ok;
}

bool TCaus::chiusura() const 
{ return _rec.get_char("MOVAP") == 'C'; }

bool TCaus::apertura() const 
{ return _rec.get_char("MOVAP") == 'A'; }


///////////////////////////////////////////////////////////
// TSaldi_list
///////////////////////////////////////////////////////////

//  
// Cerca l'esercizio precedente di EseCorr
// Se EseCorr e' gia' il primo ritorna 0
//
const int EsePre(const int EseCorr)
{
  TEsercizi_contabili esc;
  return esc.pred(EseCorr);
}

// aep e' l'esercizio precedente
TSaldi_list::TSaldi_list(int gr, int co, int aec, int aep_par)
{
  TLocalisamfile    cf(LF_SALDI);
  bool              force;
  TString16         key;
  int               aep = aep_par;
  
  destroy();
  cf.zero();

  // Se non passo l'anno precedente lo devo comunque calcolare
  if (aep_par == 0)
    aep = EsePre(aec);
  
  cf.setkey(2);
  cf.put(SLD_GRUPPO,gr);
  cf.put(SLD_CONTO,co);

  for (cf.read(_isgteq);!cf.eof();cf.next())
  {             
    if (!cf.get_bool(SLD_FLSCA))
    {
      const int ae = cf.get_int(SLD_ANNOES);
      const int  g = cf.get_int(SLD_GRUPPO);
      const int  c = cf.get_int(SLD_CONTO);        
      const long s = cf.get_long(SLD_SOTTOCONTO);
      
      if (g != gr || c != co) break;
      if (ae != aec && ae != aep) continue;
      
      TRectype r(cf.curr());   
      key.format("%3d%3d%6ld", g, c, s);
      
      // Se avevo chiesto anche l'es. prec. puo' darsi che l'abbia gia' trovato
      force = !aep_par;
      add((const char*) key, r, force);      
    }
  }
}

TRectype* TSaldi_list::saldi() const 
{ 
  TObject* o = ((TAssoc_array*)this)->get();
  return (TRectype*)o; 
}

///////////////////////////////////////////////////////////
// TSaldo
///////////////////////////////////////////////////////////

TSaldo::TSaldo() : _saldi(LF_SALDI), _saldoiniziale(ZERO), _saldo_iniziale(ZERO),
                   _prg_dare(ZERO), _prg_avere(ZERO), _saldo(ZERO), _annoes(0),
                   _indbil(0), _prec(FALSE), _movimentato(FALSE), _significativo(FALSE),
                   _rec_presente_ec(FALSE), _rec_presente_ep(FALSE),
                   _causali_apertura(LF_CAUSALI, CAU_MOVAP)

{}

real TSaldo::saldofin_esprec(int annoes, int g, int c, long s, bool saldo_chiusura, bool mov_prec) 
{
  const int annoesprec = EsePre(annoes);
  _significativo = FALSE;

  if (!ricerca_progr_prec(annoesprec, g, c, s)) // non ci sono esercizi prima del primo
    return ZERO;  
  
  const char flag      = _saldi.get(SLD_FLAGSALINI)[0];
  const real saldo     = _saldi.get_real(SLD_SALDO);
  const real pdare     = _saldi.get_real(SLD_PDARE);
  const real pavere    = _saldi.get_real(SLD_PAVERE); 
  const real pdarepro  = _saldi.get_real(SLD_PDAREPRO);
  const real paverepro = _saldi.get_real(SLD_PAVEREPRO);
  const char flagsf    = _saldi.get_char(SLD_FLAGSALFIN);
  const real saldosf   = _saldi.get_real(SLD_SALDOFIN);
  
 	real tot = pdare-pavere;

  if (flag == 'D') tot += saldo;
  else tot -= saldo;   
  
  if (saldo_chiusura)      // W96SALDI del 18-07-96
  {                        // Ho aggiunto il flag saldo_chiusura con valore di
    if (flagsf == 'D')     // default a FALSE, perche' il saldo finale dell' esercizio
      tot += saldosf;      // precedente va considerato solamente nel calcolo dei 
    else                   // progressivi precedenti nella stampa mastrini,
      tot -= saldosf;      // che e' l'unico programma ad usare la funzione
  }                        // passandogli come flag saldo_chiusura il valore TRUE.

  _significativo = (tot != 0);
  return tot;  
} 

//richiamata nel bilancio a sez.contr per data limite
//in realta' calcola il saldo finale es.prec
real TSaldo::calcola_saldo_iniziale(int g,int c,long s,int indbil)
{
  real saldoini;
  _significativo = TRUE; 
  
  _saldi.zero();
  _saldi.put(SLD_GRUPPO,g);
  _saldi.put(SLD_CONTO,c);
  _saldi.put(SLD_SOTTOCONTO,s);
  _saldi.put(SLD_ANNOES,_annoes);
  _saldi.put(SLD_FLSCA,"");
  
  if (_rec_presente_ec = (_saldi.read() == NOERR))
    saldoini  = _saldi.get_real(SLD_SALDO);
  
  _significativo = _rec_presente_ec && saldoini != ZERO;
                        
  if (saldoini != ZERO) //non va considerato!!! Vedi appunti
    _saldo_iniziale = ZERO;
  
  if (saldoini == ZERO)
  { 
    if (indbil == 1 || indbil == 2 || indbil == 5)
    {
      _prec = TRUE;
      saldoini = saldofin_esprec(_annoes, g, c, s);
    }
    _saldo_iniziale = saldoini;  
  }  
  return _saldo_iniziale; 
}

const char* TSaldo::causale_chiusura_es()
{
  TConfig conf(CONFIG_DITTA);
  return conf.get("CoCaCh");
}

const char* TSaldo::causale_apertura_es()
{
  TConfig conf(CONFIG_DITTA);
  return conf.get("CoCaAp");
}

bool TSaldo::leggi_mov(long nr)
{
  TLocalisamfile mov(LF_MOV);
//  mov.zero();
  mov.put (MOV_NUMREG, nr);
  const bool ok = mov.read() == NOERR;
  if (ok)
  {
    _codcaus  = mov.get(MOV_CODCAUS);
    _datareg  = mov.get(MOV_DATAREG);
    _provv    = mov.get(MOV_PROVVIS); // _provv.trim();
    _datacomp = mov.get(MOV_DATACOMP);
  } 
  else
    NFCHECK("Testata assente: %ld", nr);
  return ok; 
}

//per bilancio scalare (ovvero a sezioni contrapposte) per data limite
bool TSaldo::data_limite_bilancio(int bilancio, int g, int c, long s, const TDate& data_inf, 
                                  const TDate& data_sup, int indbil, int stp_prov)
{
  TLocalisamfile rmov(LF_RMOV);
  
  _saldo_iniziale  = ZERO;
  _saldo           = ZERO;
  _movimentato     = FALSE;
  _rec_presente_ep = FALSE;
  _rec_presente_ec = FALSE; 
  _prec            = FALSE;
  
  rmov.setkey(2);
  rmov.zero();
  rmov.put(RMV_GRUPPO,g);
  rmov.put(RMV_CONTO,c);
  rmov.put(RMV_SOTTOCONTO,s);
  
  // Anche se non movimentato vado a vedere il saldo 
  if (stp_prov != 3)
    _saldo = calcola_saldo_iniziale(g,c,s,indbil);  

#ifdef DBG    
  long num_rec = 0;
  const clock_t clock_start = clock();  
#endif
 
  for (rmov.read(_isgteq); !rmov.eof(); rmov.next())
  {    
    const int  gruppo     = rmov.get_int(RMV_GRUPPO);
    const int  conto      = rmov.get_int(RMV_CONTO);
    const long sottoconto = rmov.get_long(RMV_SOTTOCONTO);
    if (gruppo != g || conto != c || sottoconto != s)
      break;

#ifdef DBG    
    num_rec++;
    if ((num_rec & 0x7F) == 0)
    {               
      const double sec = (clock() - clock_start) / CLOCKS_PER_SEC;
      if (sec > 0.0)
      {
        TString80 msg;
        msg.format("%ld records at %ld rec/sec", num_rec, long(num_rec/sec));
        xvt_statbar_set(msg);
        do_events();
      }  
    }
#endif
    
    const long num_reg    = rmov.get_long(RMV_NUMREG);
    TDate data_mov;
    
    // Leggo la testata
    leggi_mov(num_reg);    

    if (bilancio == DataLimite)
      data_mov = _datacomp;
    else
    {
      if (_annoes == 0)                 
        data_mov = _datareg;
      else              
        data_mov = _datacomp;
    } 

    if (data_mov < data_inf || data_mov > data_sup)
      continue;                         
    
    // "Se la causale del movimento e' di chiusura, 
    //  o di apertura il movimento non va considerato"
    if (_codcaus.not_empty())
    {
      const TString& movap = _causali_apertura.decode(_codcaus);
      if (movap == "C") 
        continue;                   
    }    
    
    //bilancio normale (non comprende i provvisori) ?
    if (stp_prov == 1 && _provv.not_empty()) 
      continue;
    
    //bilancio dei soli provvisori ?
    if (stp_prov == 3 && _provv.empty())     
      continue;                                             
    
    const char sezione    = rmov.get_char(RMV_SEZIONE);
    const real importo    = rmov.get(RMV_IMPORTO);

    // I mov. di puro riferimento (= con importo = 0) vanno scartati
    if (importo == ZERO) 
      continue;
    
    _movimentato = TRUE;

    if (sezione == 'D')  
      _saldo += importo;
    else 
      _saldo -= importo;
  }

#ifdef DBG                 
  xvt_statbar_refresh();
#endif

  return _movimentato;  
}


//per bilancio di verifica all'ultima immissione
bool TSaldo::ultima_immissione_verifica(int annoes,int g,int c,long s,int indbil,int stp_prov)
{
  //Si considerano i saldi e non piu' i movimenti
  char sezione,sezsf; 
  int  gruppo, conto, annoe;
  long sottoconto;
  real pdarepro, paverepro,saldofin;
  bool esito = FALSE;
  
  _saldo_iniziale = ZERO; 
  _saldoiniziale  = ZERO;
  _prg_dare       = ZERO;
  _prg_avere      = ZERO;
  _saldo          = ZERO;          
  saldofin        = ZERO;

  _saldi.zero();
  _saldi.put(SLD_ANNOES,annoes);
  _saldi.put(SLD_GRUPPO,g);
  _saldi.put(SLD_CONTO,c);
  _saldi.put(SLD_SOTTOCONTO,s);
  _saldi.put(SLD_FLSCA, "");
  
  if (_saldi.read() == NOERR)
  { 
    annoe           = _saldi.get_int(SLD_ANNOES);
    gruppo          = _saldi.get_int(SLD_GRUPPO);
    conto           = _saldi.get_int(SLD_CONTO);
    sottoconto      = _saldi.get_long(SLD_SOTTOCONTO);
    _saldo_iniziale = _saldi.get_real(SLD_SALDO);
    _prg_dare       = _saldi.get_real(SLD_PDARE);
    _prg_avere      = _saldi.get_real(SLD_PAVERE);
    pdarepro        = _saldi.get_real(SLD_PDAREPRO);
    paverepro       = _saldi.get_real(SLD_PAVEREPRO);
    sezione         = _saldi.get_char(SLD_FLAGSALINI);
    sezsf           = _saldi.get_char(SLD_FLAGSALFIN);    // W96SALDI del 19-06-96 modifica richiesta
    saldofin        = _saldi.get_real(SLD_SALDOFIN);      // da PATRIZIA 
    
    if (stp_prov == 1)  //bilancio normale (senza provvisori)
      if (_saldo_iniziale == ZERO && _prg_dare == ZERO && _prg_avere == ZERO) 
        return esito;
//    if (stp_prov == 0 && paverepro == ZERO)   
    if (stp_prov == 3 && paverepro == ZERO && pdarepro == ZERO) // Modifica del 24-09-96 errore MI0890.  
		{
      _saldo = _prg_dare = _prg_avere = ZERO;    // N.B. Non e' detto che funzioni sempre!!!!!!
      return esito;
		}      
    
    if (sezione == 'A') _saldo_iniziale = -_saldo_iniziale;   
    
    if (sezsf == 'A') saldofin = -saldofin;                // W96SALDI del 19-06-96
    
    _saldoiniziale = _saldo_iniziale; //saldo iniziale presente sul record saldi
    //non comprensivo del saldo finale es.precedente
    
    if (stp_prov != 3)
      if (indbil == 1 || indbil == 2 || indbil == 5)      
        if (_saldo_iniziale == ZERO)
          _saldo_iniziale += saldofin_esprec(annoes,gruppo,conto,sottoconto);   

    esito = TRUE;
    
    switch (stp_prov)
    {
    case 1: 
      _saldo = _saldo_iniziale + _prg_dare - _prg_avere + saldofin;     // W96SALDI del 19-06-96
      break;
    case 2:
      _saldo = _saldo_iniziale + _prg_dare - _prg_avere + pdarepro - paverepro + saldofin;  // W96SALDI del 19-06-96
      if (pdarepro != ZERO)      // Modifica del 24-09-96 errore MI0890: nel caso in cui i progressivi
        _prg_dare = pdarepro;    // pdarepro o paverepro sono compilati sono in presenza di un movimento
      if (paverepro != ZERO)     // provvisorio, dunque li trasferisco nei progressivi che poi uso nel
        _prg_avere = paverepro;  // CG1500 per la stampa.
      break;
    case 3:
      _saldo = pdarepro - paverepro; 
      _prg_dare  = pdarepro;     // Idem come sopra.
      _prg_avere = paverepro;    // N.B. Non e' detto che funzioni sempre!!!!!!
      break;
    default:
      break;  
    }  
  }
  return esito;
}  

//per bilancio a sezioni contrapposte all'ultima immissione   
// W96SALDI in questa funzione e' stato aggiunto il parametro saldo_chiusura che di default
// e' TRUE. A cosa serve ? Serve per includere nel calcolo del saldo all' ultima immissione
// anche il saldo finale compilato nei movimenti di chiusura (se non venisse considerato i conti
// risulterebbero aperti); siccome alcuni programmi (esempio il bilancio IV dir. CEE) non ne 
// devono tenere conto, si e' data la possibilita' di usare la funzione passandogli il parametro a FALSE.
// Modifica del 09-07-96
bool TSaldo::ultima_immissione_bilancio(int annoes,int g,int c,long s,int indbil,int stp_prov,bool saldo_chiusura)
{
  //Si considerano i saldi e non piu' i movimenti
  char sezione; 
  int  gruppo, conto, annoe;
  long sottoconto;
  real pdarepro, paverepro;  
  real saldofinale;
  char flagsf;
  bool esito = FALSE;
  
  _saldo_iniziale = ZERO;
  _prg_dare       = ZERO;
  _prg_avere      = ZERO;
  _saldo          = ZERO;
  _rec_presente_ec = FALSE;
  _rec_presente_ep = FALSE; 
  _prec = FALSE;
  
  _saldi.zero();
  _saldi.put(SLD_ANNOES,annoes);
  _saldi.put(SLD_GRUPPO,g);
  _saldi.put(SLD_CONTO,c);
  _saldi.put(SLD_SOTTOCONTO,s);
  _saldi.put(SLD_FLSCA, "");  
  
  if (_saldi.read() == NOERR)
  {
    annoe           = _saldi.get_int(SLD_ANNOES);
    gruppo          = _saldi.get_int(SLD_GRUPPO);
    conto           = _saldi.get_int(SLD_CONTO);
    sottoconto      = _saldi.get_long(SLD_SOTTOCONTO);
    _saldo_iniziale = _saldi.get_real(SLD_SALDO);
    _prg_dare       = _saldi.get_real(SLD_PDARE);
    _prg_avere      = _saldi.get_real(SLD_PAVERE);
    pdarepro        = _saldi.get_real(SLD_PDAREPRO);
    paverepro       = _saldi.get_real(SLD_PAVEREPRO);
    sezione         = _saldi.get_char(SLD_FLAGSALINI);
    flagsf          = _saldi.get_char(SLD_FLAGSALFIN);
    saldofinale     = _saldi.get_real(SLD_SALDOFIN);
    
    if (stp_prov == 1)   //bilancio normale (senza provvisori)
      esito = (_saldo_iniziale != ZERO || _prg_dare != ZERO || _prg_avere != ZERO);
    
    if (stp_prov == 2)  //bilancio globale (con provvisori)
      esito = (_saldo_iniziale != ZERO || _prg_dare != ZERO || _prg_avere != ZERO
               || pdarepro != ZERO || paverepro != ZERO); 
    
    if (stp_prov == 3)  //bilancio dei soli mov. provvisori
      esito = (pdarepro != ZERO || paverepro != ZERO); 
    
    if (sezione == 'A') _saldo_iniziale = -_saldo_iniziale;
    
    if (saldo_chiusura)               // W96SALDI modifica inserita per il discorso di inclusione oppure
      if (flagsf == 'A')              // no del saldo di chiusura inserita il 09-07-96
        saldofinale = -saldofinale;
        
    _rec_presente_ec = esito;
  }
  
  if (stp_prov != 3)
    if (indbil == 1 || indbil == 2 || indbil == 5)      
      if (_saldo_iniziale == ZERO)  
      {
        _prec = TRUE;
        _saldo_iniziale += saldofin_esprec(annoes,g,c,s);
      }
  
  if (stp_prov == 1)
    _saldo = _saldo_iniziale + _prg_dare - _prg_avere;  
  
  if (stp_prov == 2)
    _saldo = _saldo_iniziale + _prg_dare - _prg_avere + pdarepro - paverepro;  
  
  if (stp_prov == 3)
    _saldo = pdarepro - paverepro;  
  
  if (saldo_chiusura)        // W96SALDI modifica inserita per il discorso di inclusione oppure
    _saldo += saldofinale;   // no del saldo di chiusura inserita il 09-07-96
    
  return esito;
} 

bool TSaldo::ricerca_progr_prec (int annoesprec, int g, int c, long s)
{
  if (annoesprec == 0)
    _rec_presente_ep = FALSE;
  else
  {  
    const int oldkey = _saldi.getkey();
    _saldi.setkey(1);
    _saldi.zero(); 
    _saldi.put(SLD_ANNOES,annoesprec);
    _saldi.put(SLD_GRUPPO,g);
    _saldi.put(SLD_CONTO,c);
    _saldi.put(SLD_SOTTOCONTO,s);
    _saldi.put(SLD_FLSCA, "");
    _rec_presente_ep = _saldi.read() == NOERR; 
    _saldi.setkey(oldkey);
  }
  return _rec_presente_ep; 
}

//calcolo dei progressivi attuali (normali o eliminati) 
bool TSaldo::prg_saldo(int annoes, TConto& conto, real& prgdare, real& prgavere, bool scar)
{
  _saldi.zero();
  _saldi.put(SLD_GRUPPO,conto.gruppo());
  _saldi.put(SLD_CONTO,conto.conto());
  _saldi.put(SLD_SOTTOCONTO,conto.sottoconto());
  _saldi.put(SLD_ANNOES,annoes);
  _saldi.put(SLD_FLSCA, scar);  

  bool ok = _saldi.read() == NOERR; 
  
  if (ok)
  { 
    const char flagsalini = _saldi.get_char(SLD_FLAGSALINI);
    const real saldoini    = _saldi.get_real(SLD_SALDO);
    prgdare = _saldi.get_real(SLD_PDARE);
    prgavere = _saldi.get_real(SLD_PAVERE);
    
    if (flagsalini == 'D')
      prgdare  += saldoini ;
    else
      prgavere += saldoini;  
  }
  return ok;
}