#include <stdlib.h>

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

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

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

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

TMovimentoPN::TMovimentoPN()
: TRelation(LF_MOV), _cg(LF_RMOV, "NUMRIG"), _iva(LF_RMOVIVA, "NUMRIG")
{
  add(LF_RMOV, "NUMREG=NUMREG");
  add(LF_RMOVIVA, "NUMREG=NUMREG");
}

void TMovimentoPN::destroy_rows(long num)
{                    
  _cg.destroy_rows();
  _cg.renum_key("NUMREG", num);
  _iva.destroy_rows();
  _iva.renum_key("NUMREG", num);
}


TRectype& TMovimentoPN::cg(int i)
{
  return _cg.row(i >= 0 ? i+1 : -1, TRUE);
}

TRectype& TMovimentoPN::iva(int i)
{
  return _iva.row(i >= 0 ? i+1 : -1, TRUE);
}

int TMovimentoPN::read_mov_rows()
{                   
  const long numreg = lfile().get_long(MOV_NUMREG);
  
  TRectype cgfilter(LF_RMOV);
  cgfilter.zero(); 
  cgfilter.put(RMV_NUMREG, numreg);
  _cg.read(cgfilter);
  
  TRectype ivafilter(LF_RMOVIVA);
  ivafilter.zero(); 
  ivafilter.put(RMI_NUMREG, numreg);
  _iva.read(ivafilter);

  return _cg.rows();
}


int TMovimentoPN::read(TIsamop op, TReclock lockop, TDate& atdate)
{
  const int err = TRelation::read(op, lockop, atdate);
  if (err == NOERR) 
  {
    _olddate = file().get("DATAREG");       // Memorizza data operazione per aggiornare i saldi
    read_mov_rows();                        // Riempie i due record array
  }  
  return err;
}

char TMovimentoPN::frequenza_versamenti(int year) const
{
  static int last_year = 0;
  static long last_firm = 0;
  static char last_freq = ' ';
  
  const long firm = prefix().get_codditta();
  
  if (firm != last_firm || year != last_year)
  {
    TString16 key; key.format("%05ld%d", firm, year);
    TTable lia("%LIA");
    lia.put("CODTAB", key);
    if (lia.read() != NOERR)
    { 
      TLocalisamfile nditte(LF_NDITTE);
      nditte.put("CODDITTA", firm);
      nditte.read();
      last_freq = nditte.get_char("FREQVIVA");
    }
    else 
      last_freq = lia.get_char("S7");
    CHECK(last_freq == 'M' || last_freq == 'T', "Frequenza versamenti IVA assurda");
    
    last_firm = firm;  
    last_year = year;
  }
  
  return last_freq;
}  

int TMovimentoPN::date2liq(const TDate& data) const
{
  const int anno = data.year();
  int mese = data.month();
  if (frequenza_versamenti(anno) == 'T')
    mese += 2 - ((mese-1) % 3);
  return mese;  
}  


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

  const int anno = data.year();
  const int mese = date2liq(data);
  
  // Chiave di LIM: Anno (1-4), Mese (5-6)
  TString16 key; key.format("%04d%02d", anno, mese);
  TTable lim("LIM");
  lim.setkey(1);
  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.zero("B0");                  // calcolato
    lim.zero("B1");                  // definitivo
    lim.rewrite();
  }  
  
  if (reset)
  {
    const bool att_mista = registro.name().empty() ? FALSE : registro.attivita_mista();
    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;                       
      TString16 attivita(registro.attivita()); attivita.right_just(5, '0');
      chiave << data.year() << attivita << a << format("%02d", data.month());
      plm.put("CODTAB", chiave);
      if (plm.read() == NOERR)
      {
        const bool calcolato = plm.get_bool("B0");
        if (calcolato)
        {
          plm.zero("B0");
          plm.rewrite();
        }  
      }  
    }
  }
  
  return calcolata;
}


int TMovimentoPN::registra(bool re, bool force)
{
  int err = re ? TRelation::rewrite(force) : TRelation::write(force);
  if (err != NOERR) 
    return err;

  const TRectype& m = curr();
  const long numreg = m.get_long("NUMREG");
  
  if (!re)
    _cg.renum_key("NUMREG", numreg);
  err = _cg.write(re);
  if (err != NOERR) 
    return err;

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

  for (int i = 0 ; i < iva_items(); i++)
  {
    TRectype& r = iva(i);
    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);
  }
  
  if (!re)
    _iva.renum_key("NUMREG", numreg);
  err = _iva.write(re);
  if (err != NOERR) 
    return err;


  // Aggiorna data registrazione e protocollo IVA sul registro
  const TDate datareg(m.get("DATAREG"));
  if (reg.not_empty())
  {                             
    const long protiva = m.get_long("PROTIVA");
    const long uprotiva = m.get_long("UPROTIVA");
    const long max = protiva > uprotiva ? protiva : uprotiva;
    registro.update(max, datareg);
  }      
  
  // Aggiorna flags di ricalcolo liquidazione
  
  controlla_liquidazione(datareg, registro, TRUE);
  if (re && datareg != _olddate)
    controlla_liquidazione(_olddate, registro, TRUE);

  return err;
}


int TMovimentoPN::write(bool force, TDate&)
{
  return registra(FALSE, force);
}


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


int TMovimentoPN::remove(TDate&)
{         
  int err = _cg.remove();
  
  if (err == NOERR)
    err = _iva.remove();

  if (err == NOERR)
    err = TRelation::remove();
  
  if (err == NOERR)
  {                        
    const TRectype& m = curr();
    const TDate datareg(m.get("DATAREG"));
    const int annoiva = m.get_int("ANNOIVA");
    const TString16 reg(m.get_str("REG"));
    TRegistro registro(reg, annoiva);
    controlla_liquidazione(datareg, registro, TRUE);
  }                           
  
  return err;
}

