#include <stdlib.h>

#include <xvtmacro.h>
#include <applicat.h>
#include <tabutil.h>

#include "cg2101.h"
#include "cg2103.h"

#include <mov.h>
#include <rmov.h>
#include <rmoviva.h>


// Calcola l'anno di esercizio di una data                                
// Certified 99%
int date2esc(const TDate& d, int* prevesc)
{                   
  if (prevesc) *prevesc = 0;
  TTable esc("ESC");
  for (int err = esc.first(); err == NOERR; err = esc.next())
  {
    const TDate ia(esc.get("D0"));   // Data inizio esercizio
    const TDate fa(esc.get("D1"));   // Data fine esercizio
    TString16 sanno(esc.get("CODTAB")); sanno.cut(4);
    const int anno = atoi(sanno);
    if (d >= ia && d <= fa)
      return anno;
    if (prevesc) *prevesc = anno; 
  } 
  return 0;
}

///////////////////////////////////////////////////////////
// Movimento di prima nota
///////////////////////////////////////////////////////////

TMovimentoPN::TMovimentoPN()
: TRelation(LF_MOV), _oldcg(0), _oldiva(0)
{
  add(LF_RMOV, "NUMREG=NUMREG");
  add(LF_RMOVIVA, "NUMREG=NUMREG");
}

void TMovimentoPN::destroy_rows()
{
  _cg.destroy();
  _iva.destroy();
}


TRectype& TMovimentoPN::cg(int i)
{
  TRectype* r = (TRectype*)_cg.objptr(i);
  if (r == NULL)
  {
    r = new TRectype(LF_RMOV);
    _cg.add(r, i);
  }
  return *r;
}

TRectype& TMovimentoPN::iva(int i)
{
  TRectype* r = (TRectype*)_iva.objptr(i);
  if (r == NULL)
  {
    r = new TRectype(LF_RMOVIVA);
    _iva.add(r, i);
  }
  return *r;
}


int TMovimentoPN::read_mov_rows()
{
  const TLocalisamfile& rm = lfile(LF_RMOV);
  const TLocalisamfile& ri = lfile(LF_RMOVIVA);
  position_rels();

  destroy_rows();
  for(bool ok = is_first_match(LF_RMOV); ok; ok = next_match(LF_RMOV))
  {
    const int row = rm.get_int(RMV_NUMRIG) - 1;
    cg(row) = rm.curr();
  }
  _oldcg = cg_items();

  for(ok = is_first_match(LF_RMOVIVA); ok; ok = next_match(LF_RMOVIVA))
  {
    const int row = ri.get_int(RMI_NUMRIG) - 1;
    iva(row) = ri.curr();
  }
  _oldiva = iva_items();

  return NOERR;
}


int TMovimentoPN::read(TIsamop op, TReclock lockop, TDate& atdate)
{
  int err = file().read(op, lockop, atdate);
  if (err == NOERR) err = read_mov_rows();
  return err;
}


int TMovimentoPN::write_rec(bool re, const TRectype& rec, TLocalisamfile& f)
{
  if (re)
  {
    const bool scrivi = f.rewrite(rec) != NOERR;
    if (scrivi) f.write(rec);
  }
  else
  {
    f.write(rec);
  }

  return f.status();
}


int TMovimentoPN::cancella(TLocalisamfile& f, int da, int a)
{
  const long numreg = lfile().get_long(MOV_NUMREG);
  for (int i = da; i <= a; i++)
  {
    f.zero();
    f.put(MOV_NUMREG, numreg);
    f.put(RMV_NUMRIG, i);
    if (f.read(_isequal, _lock) == NOERR)
      f.remove();
  }
  return f.status();
}

char TMovimentoPN::frequenza_versamenti(int year) const
{
  static int last_year = 0;
  static char last_freq = ' ';
  
  if (year != last_year)
  {
    TString16 key;
    key << year;
    TTable lia("LIA");
    lia.put("CODTAB", key);
    if (lia.read() != NOERR)
    { 
      TLocalisamfile nditte(LF_NDITTE);
      nditte.put("CODDITTA", main_app().get_firm());
      nditte.read();
      last_freq = nditte.get_char("FREQVIVA");
    }
    else 
      last_freq = lia.get_char("S7");
    CHECK(last_freq == 'M' || last_freq == 'T', "Frequenza versamento IVA assurda");
  }
  
  return last_freq;
}  

bool TMovimentoPN::controlla_liquidazione(const TDate& data, bool reset) const
{    
  bool calcolata = FALSE;

  const int anno = data.year();
  int mese = data.month();
  if (frequenza_versamenti(anno) == 'T')
    mese += 2 - ((mese-1) % 3);
  
  // Chiave di LIM: Anno (1-4), Mese (5-6)

  TTable lim("LIM");
  TString16 key;
  key << anno << mese;
  lim.put("CODTAB", key);
  if (lim.read() == NOERR)
    calcolata = lim.get_bool("B1");  // Controlla se calcolata in definitivo
  
  if (reset && lim.get_bool("B0"))
  {
    // Resetta i flag di calcolato sulla liquidazione IVA del mese di registrazione        
    lim.put("B0", FALSE);            // calcolato
    lim.put("B1", FALSE);            // definitivo
    lim.rewrite();
  }  
  
  return calcolata;
}


int TMovimentoPN::registra(bool re, bool force)
{
  TLocalisamfile& m = lfile();
  
  const int err = write_rec(re, m.curr(), m);
  if (err != NOERR) return err;

  TLocalisamfile& rm = lfile(LF_RMOV);
  TLocalisamfile& ri = lfile(LF_RMOVIVA);

  const long numreg = m.get_long("NUMREG");

  for (int i = 0 ; i < cg_items(); i++)
  {                                  
    if (!re) cg(i).put("NUMREG", numreg);
    const int err = write_rec(re, cg(i), rm);
    if (!force && err != NOERR) return err;
  }
  if (i < _oldcg)
    cancella(rm, i+1, _oldcg);
  _oldcg = cg_items();


  const int annoiva = m.get_int("ANNOIVA");
  const TString16 reg(m.get("REG"));
  TRegistro registro(reg, annoiva);
  const bool att_mista = reg.empty() ? FALSE : registro.attivita_mista();

  for (i = 0 ; i < iva_items(); i++)
  {
    TRectype& r = iva(i);
    
    if (!re) r.put("NUMREG", numreg);        // Force correct number

    int tipoatt = 1;
    if (att_mista)
    {
      const char tipo = r.get_char("TIPOC");
      if (tipo <= ' ')               
      {
        TBill c(r.get_int("GRUPPO"), r.get_int("CONTO"), r.get_long("SOTTOCONTO"));
        tipoatt = c.tipo_att();
      }                      
    }
    r.put("TIPOATT", tipoatt);

    const int err = write_rec(re, r, ri);
    if (!force && err != NOERR) return err;
  }

  if (i < _oldiva)
    cancella(ri, i+1, _oldiva);
  _oldiva = iva_items();
  
  // Aggiorna data registrazione e protocollo IVA sul registro
  if (reg.not_empty())
  {                             
    const long protiva = m.get_long("PROTIVA");
    const long uprotiva = m.get_long("UPROTIVA");
    const TDate datareg = m.get_date("DATAREG");
    registro.update(max(protiva, uprotiva), datareg);
  }      
  
  const TDate d(m.get("DATAREG"));
  controlla_liquidazione(d, TRUE);

  const int att = att_mista ? 2 : 1;
  // Chiave di PLM: Anno (1-4), Cod. Att. (5-9), Tipo att. (10-10), Mese (11-12)
  TTable plm("PLM"); 
  for (int a = 1; a <= att; a++)
  {
    TString16 chiave;
    chiave << d.year() << registro.attivita() << a << d.month();
    plm.put("CODTAB", chiave);
    if (plm.read() == NOERR)
    {
      const bool calcolato = plm.get_bool("B0");
      if (calcolato)
      {
        plm.put("B0", FALSE);
        plm.rewrite();
      }  
    }  
  }

  return err;
}


int TMovimentoPN::write(bool force, TDate&)
{
  const TRectype& r = lfile().curr();

  _oldcg = _oldiva = 0;
  int err = registra(FALSE, force);
  
  return err;
}


int TMovimentoPN::rewrite(bool force, TDate&)
{
  return registra(TRUE, force);
}


int TMovimentoPN::remove(TDate&)
{
  TLocalisamfile& m  = lfile();
  TLocalisamfile& rm = lfile(LF_RMOV);
  TLocalisamfile& ri = lfile(LF_RMOVIVA);

  cancella(rm, 1, _oldcg);
  cancella(ri, 1, _oldiva);
  m.remove();
  _oldcg = _oldiva = 0;
  return m.status();
}

