#include "cg2103.h"
#include "cglib03.h"

#include <diction.h>
#include <recarray.h>

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

static int codind2tipodet(const TString & codind, real& perc)
{
  int tipodet = 0;
  perc = ZERO;
  if (codind.full())
  {
    const TRectype& rec = cache().get("%DET", codind);
    if (rec.empty())
    {
      if (strchr("139", codind[0]) != NULL) // Clausola di salvaguardia
      {
        tipodet = codind[0]-'0';
        perc = CENTO;
      }
    }
    else
    {
      tipodet = rec.get_int("I0");
      if (tipodet > 0)
        perc = rec.get_real("R0");
    }
  }
  return tipodet;
}
real indetraibile_al(const TString& codind, const TCausale& caus, int annodoc, int & tipodet,const bool is_liq)
{    
	real perc;

  switch (caus.iva())
  {
  case iva_acquisti:
  case nessuna_iva:
  case iva_errata: 
	  if (!is_liq && caus.reg().prorata100(annodoc)) // Se prorata = 100% e' indetraibile
	  {
		  perc = CENTO;
		  tipodet = 9;
	  }
	  else
		  tipodet = codind2tipodet(codind, perc);
    break;
  default: 
    tipodet = 0; // Vendite sempre detraibili
    break;
  }

  return perc; 
}

int analizza_IVA(const real& imptot, const real& ivatot, const real perc_ind,
								 const bool corrispettivo, const bool iva_ind_al_costo, const TString& codiva,
                 real& imp_det, real& iva_det, real& imp_ind, real& iva_ind)

{
  int flag = 0;
	
	if (perc_ind <= ZERO)
  {
    flag = 1;
    imp_det = imptot;
    iva_det = ivatot;
    if (corrispettivo && iva_det.is_zero())
    {
      const TCodiceIVA iva(codiva);
      iva_det = iva.scorpora(imp_det);
    }
    imp_ind = iva_ind = ZERO;
  }
  else
  {
		if (perc_ind >= CENTO)
    {
      flag = 2;
      imp_ind = imptot;
      iva_ind = ivatot;
      imp_det = iva_det = ZERO;
    }
    else
    {
      flag = 3;
      const int decimali = TCurrency::get_firm_dec();
      imp_ind = imptot * perc_ind / CENTO; imp_ind.round(decimali);
      imp_det = imptot - imp_ind;

      const TCodiceIVA iva(codiva);
      iva_ind = iva.imposta(imp_ind, decimali);
      iva_det = ivatot - iva_ind;
    }
    if (iva_ind_al_costo && !iva_ind.is_zero())
    {
      imp_ind += iva_ind;
      iva_ind = ZERO;
    }
  }

  return flag;
}

// Anticamente TIPODET conteneva in tipo di indetraibilita,
// ora invece trattasi di un codice di indetraibilita'
// associato ad un motivo ed una percentuale di indetraibilita'
int get_tipodet_from_rmi(const TRectype& rmi, const TRectype& mov,real& percind, const bool is_liq)
{
	const int annodoc = mov.get_date(MOV_DATAREG).year();
	const TCausale caus(mov.get(MOV_CODCAUS), annodoc);
	
  int tipodet = 0;
	percind = indetraibile_al(rmi.get(RMI_TIPODET), caus, annodoc, tipodet, is_liq);

  return tipodet;
}

///////////////////////////////////
// classe TInteressi_IVA_table   //
// per la lettura versamenti e   //
// e interessi IVA dalla tabella //
///////////////////////////////////

TInteressi_IVA_table::TInteressi_IVA_table() : TTable("%VER")
{
}

TInteressi_IVA_table::~TInteressi_IVA_table()
{
}

int TInteressi_IVA_table::read(int anno, int mese)
{
  TString8 k; k.format("%04d%02d",anno,mese);
  zero(); put("CODTAB",k);
  if (TTable::read(_isgteq) == NOERR)
  {
    const TString& cod = TTable::get("CODTAB");    
    if (cod > k && prev() != NOERR)
      zero();
  }
  else
    if (last() != NOERR)
      zero();
  return status();
}

real TInteressi_IVA_table::get(int what)
{
  TString4 fieldname;
  fieldname.format("R%d", what);
  return get_real(fieldname);
}

///////////////////////////////////////////////
// TRigaiva_array 
// Tabella per il calcolo degli imponibili Iva
///////////////////////////////////////////////

const TString& TRigaiva::descr_det() const
{
  TString& rig = get_tmp_string();
  switch (_tipodet)
  {
  case 1 : rig = TR("Indetraib. su op.es."); break;
  case 3 : rig = TR("Passaggi interni"); break;
  case 9 : rig = TR("Indetraibile art.19"); break;
  default: rig = TR("Detraibile"); break;
  }
  return rig;
}

bool TRigaiva_array::add_riga(const real& imponibile, const real& imposta, 
                              const real& imponibilep, const real& impostap, 
                              const char* codiva, int tipodet, int tipocr, 
                              bool intra, int tipoatt) 
{
  int i;
  for (i = items()-1; i >= 0; i--)
  {
    TRigaiva& r = riga(i);
    if (r._codiva==codiva && r._tipodet==tipodet && r._tipocr==tipocr && r._tipoatt==tipoatt)
    {
      r._imponibile  += imponibile;
      r._imposta     += imposta;
      r._imponibilep += imponibilep;
      r._impostap    += impostap;
      break;
    }
  }
  if (i < 0)
  {
    TRigaiva* r = new TRigaiva(imponibile,imposta,imponibilep,impostap,codiva,tipodet,tipocr,intra,tipoatt);
    add(r);
  }
  return i >= 0;
}

bool TRigaiva_array::add_riga(const TRectype& iva)
{
  const real impo  = iva.get_real(RMI_IMPONIBILE);
  const real impos = iva.get_real(RMI_IMPOSTA);
  bool ok = !impo.is_zero() || !impos.is_zero();
  if (ok)
  {
    real percind; 
    const TString & codind     = iva.get(RMI_TIPODET);
    const int tipodet     = codind2tipodet(codind, percind);
    const TString4 codiva = iva.get(RMI_CODIVA);
    const int tipocr      = iva.get_int (RMI_TIPOCR);
    const bool intra      = iva.get_bool(RMI_INTRA);
    const int tipoatt     = iva.get_int (RMI_TIPOATT);

    if (percind > ZERO && percind < CENTO)
    {
      const int dec = TCurrency::get_firm_dec();
      real impo_ind  = impo * percind / CENTO; impo_ind.round(dec);
      const real impo_det  = impo - impo_ind;

      const TCodiceIVA iva(codiva);

			real impos_ind =  iva.imposta(impo_ind, dec);
			const real impos_det = impos - impos_ind;

      ok = add_riga(impo_det,impos_det,ZERO,ZERO,codiva,0,tipocr,intra,tipoatt);
      ok &= add_riga(impo_ind,impos_ind,ZERO,ZERO,codiva,tipodet,tipocr,intra,tipoatt);
    }
    else
    {
      ok = add_riga(impo,impos,ZERO,ZERO,codiva,tipodet,tipocr,intra,tipoatt);
    }
  }
  return ok;
}

///////////////////////////////////////////////
// TRiga_array 
///////////////////////////////////////////////
                               
bool TRiga_array::add_riga(const real& imponibile, const real& imposta, 
                           const real& implordo, const real& imponibilep, 
                           const real& impostap, const real& implordop, 
                           const char* codiva) 
{
  bool found = false;
  for (int i = 0; i < items(); i++)
  {
    TRiga& r = riga(i);
    if (r._codiva==codiva) 
    {
      found = true;
      r._imponibile  += imponibile;
      r._imposta     += imposta;
      r._implordo    += implordo;  
      r._imponibilep += imponibilep;
      r._impostap    += impostap;
      r._implordop   += implordop;
      break;
    }
  }
  if (!found)
  {                                                
    TRiga* r = new TRiga(imponibile,imposta,implordo,imponibilep,impostap,implordop,codiva);
    add(r);
  }
  return found;
}

///////////////////////////////////////////////
// TDociva_array
///////////////////////////////////////////////

bool TDociva_array::add_riga(const char* _descrdociva, const real& _importo,const int _natdoc) 
{
  bool found = false;
  for (int i = 0; i < items(); i++)
  {
    TDociva& r = riga(i);
    if (r._descrdoc==_descrdociva) 
    {
      found = true;
      if ((r._ndoc == 1)||(r._ndoc == 2)||(r._ndoc == 9))//||(r._ndoc == 4))
        r._totdociva += _importo;
    }
  }
  if (!found)
  {
    if ((_natdoc == 1)||(_natdoc == 2)||(_natdoc == 9))//||(_natdoc == 4))
    {
      TDociva* r = new TDociva(_descrdociva,_importo,_natdoc);
      add(r);
    }
  }
  return found; 
}  

bool TTipodoc_array::add_riga(const char* tipodoc, const char* descrdoc, const real& totdoc) 
{
  bool found = false;
  for (int i = 0; i < items(); i++)
  {
    TTipodoc& r = (TTipodoc&)(*this)[i];
    if (r._tipodoc==tipodoc) 
    {
      found = true;
      r._totdoc += totdoc;
    }
  }
  if (!found)
  {
    TTipodoc* r = new TTipodoc(tipodoc,descrdoc,totdoc);
    add(r);
  }
  return found;
}

///////////////////////////////////////////////////////////
// Arrotondamenti iva 
///////////////////////////////////////////////////////////

TRound_mode TIva_round::_def_mode = rm_unknown;
int TIva_round::_def_decimals = 0;

void TIva_round::set_default_mode(TRound_mode m, int d)
{
  _def_mode = _mode = m;
  _def_decimals = _decimals = d;
}

void TIva_round::set_mode(TRound_mode m, int d)
{
  _mode = m;
  _decimals = d;
}

void TIva_round::set_default_iva_mode(int year, bool declaration, long ditta)
{                               
  if (year < 1990)
    year = TDate(TODAY).year();

  if (year >= 2002 && is_euro_value(NULL))
  {
    if (ditta <= 0)
      ditta = prefix().get_codditta();
    TString16 key; key.format("%05ld%04d", ditta, year);
    const TRectype& lia = cache().get("%LIA", key);
    const int dec = lia.get_int(declaration ? "I2" : "I1");
    set_default_mode(rm_round, dec);
  }
  else
    set_default_mode(rm_millelire, -3);
}
  
void TIva_round::round(real& n) const
{
  CHECK(_mode != rm_unknown, "Non � stato impostato il metodo di arrotondamento");
  switch (_mode)
  {
  case rm_ceil: 
    n.ceil(_decimals); 
    break;
  case rm_millelire: 
    n -= 0.0001; // Le 500 lire vanno arrontondate per difetto
  default: 
    n.round(_decimals); 
    break;
  }
}

TIva_round::TIva_round()
{
  _mode = _def_mode;
  _decimals = _def_decimals;
}