/* ModeloDeclaracao - Decompiled by JODE
 * Visit http://jode.sourceforge.net/
 */
package serpro.ppgd.irpf;
import serpro.ppgd.negocio.ObjetoNegocio;
import serpro.ppgd.negocio.Valor;

public abstract class ModeloDeclaracao extends ObjetoNegocio
{
  /* NOTE: Em lib/resources/aliquotas.xml a partir do IRPF2021.
     valorAjusteLimiteAnualFaixa[1234] e
     valorAjusteDescontoAnualFaixa[1234] ou procure pelas "tabelas
     progressivas anuais" ou de "incidência anual" em
     https://www.gov.br/receitafederal/pt-br/assuntos/meu-imposto-de-renda/tabelas.
     Uma APROXIMAÇÃO pode ser feita com base na Lei nº 11.482/2007,
     com cálculos conforme Art. 1º, incisos X, XI e parágrafo único.

     IMPORTANTE: Sempre consulte o programa de referência ou a
     primeira página, evitando usar a aproximação conseguida na lei
     citada, para evitar diferenças nos valores, principalmente
     tratando-se dos descontos.

     A propriedade que esses descontos buscam preservar é de que, no
     limite entre duas faixas de taxação vizinhas, o imposto seja o
     mesmo, calculando com qualquer das fórmulas das duas faixas que
     ali se encontram, de modo que o imposto calculado seja uma função
     contínua e progressiva.

     Noutras palavars, dada a tabela:

     F   Receita (R)  Alíquota (A)    Desconto (D)
     0          0,00          0,0%            0,00
     1     26.963,20          7,5%        2.022,24
     2     33.919,80         15,0%        4.566,23
     3     45.012,60         22,5%        7.942,17
     4     55.976,16         27,5%       10.740,98

     O objetivo é que R[F] * A[F] - D[F] = R[F] * A[F-1] - D[F-1]

     Com esses valores, usados pelo IRPF, essa propriedade se mantém.

     Somando os descontos mensais, não necessariamente, ainda que essa
     propriedade seja observada nas duas tabelas mensais.

     O motivo da divergência é que, ao anualizar a renda e aplicar uma
     mesma alíquota, aplica-se alíquota diferente da devida para
     valores que estejam entre os limites antigo e o novo.

     (É como aquele quebra-cabeça aritmético em que um sujeito fica
     tomando conta de duas banquinhas de frutas, cada qual vendendo
     lotes de tamanhos diferentes por preços diferentes, resolve somar
     os lotes e os preços e se surpreende que o resultado da venda dá
     mais ou menos que o esperado)

     O desconto ajustado, usado pelo IRPF, desfaz a distorção da
     alíquota limítrofe.

     O "desconto", na verdade, é meio que uma otimização das contas
     para alcançar a continuidade.  Na real, a forma de calcular o
     imposto seria assim:

     Seja V a receita, I o imposto devido e F = 1 a faixa na tabela
     acima, então enquanto V > R[F]:

     I += (V - R[F]) * (A[F] - A[F-1])
     F += 1

     Noutras palavras, aplica-se cada alíquota progressiva somente à
     porção da renda que ativa aquela alíquota.

     Os "descontos" D[F] = D[F-1] + (R[F] - R[F-1]) * (A[F] - A[F-1]),
     simplificam as contas ao permitir fazer a conta aplicando uma só
     alíquota, capturando em cada linha da tabela a fração daquela
     faixa de renda sobre a qual menores alíquotas incidiriam.

     Mas essa formulação em termos de "descontos", assim como os lotes
     de frutas a preços e quantidades diferentes, não garante a
     possibilidade de soma simples de descontos diferentes.  É preciso
     voltar na propriedade original e recalcular.

  */
  public static final String LIMITE_ANUAL_27_MEIO_PORCENT = "55.976,16";
  public static final String LIMITE_ANUAL_22_MEIO_PORCENT = "45.012,60";
  public static final String LIMITE_ANUAL_15_PORCENT = "33.919,80";
  public static final String LIMITE_ANUAL_7_MEIO_PORCENT = "26.963,20";
  public static final String DESCONTO_27_MEIO_PORCENT = "10.740,98";
  public static final String DESCONTO_22_MEIO_PORCENT = "7.942,17";
  public static final String DESCONTO_15_PORCENT = "4.566,23";
  public static final String DESCONTO_7_MEIO_PORCENT = "2.022,24";
  public static final String NOME_TOTAL_REND_RECEB_MAIS_EXTERIOR = "Total de Rendimentos Recebidos";
  public static final String NOME_TOTAL_LIVRO_CAIXA_TIT_DEP = "Total Livro Caixa - TIT + DEP";
  protected DeclaracaoIRPF declaracaoIRPF = null;
  protected Valor impostoDevido = new Valor (this, "");
  protected Valor impostoDevidoII = new Valor (this, "");
  protected Valor aliquotaEfetiva = new Valor (this, "");
  protected Valor baseCalculo = new Valor (this, "");
  protected Valor saldoImpostoPagar = new Valor (this, "");
  protected Valor impostoRestituir = new Valor (this, "");
  protected Valor rendRecebidoExterior = new Valor (this, "");
  protected Valor totalRendRecebidosMaisExterior = new Valor (this, "Total de Rendimentos Recebidos");
  protected Valor totalLivroCaixa = new Valor (this, "Total Livro Caixa - TIT + DEP");
  protected Valor totalDoacoesCampanhasEleitorais = new Valor (this, "");
  
  public ModeloDeclaracao (DeclaracaoIRPF dec)
  {
    declaracaoIRPF = dec;
    aliquotaEfetiva.setPorcentagem (true);
    totalRendRecebidosMaisExterior.setReadOnly (true);
  }
  
  public Valor getTotalRendRecebidosMaisExterior ()
  {
    return totalRendRecebidosMaisExterior;
  }
  
  public Valor getTotalLivroCaixa ()
  {
    return totalLivroCaixa;
  }
  
  public Valor calculaImposto (Valor _baseCalculo)
  {
    Valor retorno = new Valor ();
    /* FIXME: cálculos para declaração de espólio e saída não usam
       todos os meses.  */
    if (_baseCalculo.comparacao ("<=", LIMITE_ANUAL_7_MEIO_PORCENT))
      retorno.clear ();
    else if (_baseCalculo.comparacao ("<=", LIMITE_ANUAL_15_PORCENT))
      {
	Valor imposto = new Valor ();
	imposto.setConteudo (_baseCalculo);
	imposto.converteQtdCasasDecimais (3);
	imposto.setConteudo (imposto.operacao ('*', "0,075"));
	imposto.append ('-', DESCONTO_7_MEIO_PORCENT);
	imposto.converteQtdCasasDecimais (2);
	retorno.setConteudo (imposto);
      }
    else if (_baseCalculo.comparacao ("<=", LIMITE_ANUAL_22_MEIO_PORCENT))
      {
	Valor imposto = new Valor ();
	imposto.setConteudo (_baseCalculo);
	/* Aumentar a precisão é indispensável nas alíquotas
	   quebradas.  Aqui, não deve fazer diferença, mas pela
	   uniformidade e linearidade, façamos igual.  */
	imposto.converteQtdCasasDecimais (3);
	imposto.setConteudo (imposto.operacao ('*', "0,15"));
	imposto.append ('-', DESCONTO_15_PORCENT);
	imposto.converteQtdCasasDecimais (2);
	retorno.setConteudo (imposto);
      }
    else if (_baseCalculo.comparacao ("<=", LIMITE_ANUAL_27_MEIO_PORCENT))
      {
	Valor imposto = new Valor ();
	imposto.setConteudo (_baseCalculo);
	imposto.converteQtdCasasDecimais (3);
	imposto.setConteudo (imposto.operacao ('*', "0,225"));
	imposto.append ('-', DESCONTO_22_MEIO_PORCENT);
	imposto.converteQtdCasasDecimais (2);
	retorno.setConteudo (imposto);
      }
    else
      {
	Valor imposto = new Valor ();
	imposto.setConteudo (_baseCalculo);
	imposto.converteQtdCasasDecimais (3);
	imposto.setConteudo (imposto.operacao ('*', "0,275"));
	imposto.append ('-', DESCONTO_27_MEIO_PORCENT);
	imposto.converteQtdCasasDecimais (2);
	retorno.setConteudo (imposto);
      }
    return retorno;
  }
  
  public Valor getImpostoDevido ()
  {
    return impostoDevido;
  }
  
  public Valor getBaseCalculo ()
  {
    return baseCalculo;
  }
  
  public Valor getAliquotaEfetiva ()
  {
    return aliquotaEfetiva;
  }

  public Valor getSaldoImpostoPagar ()
  {
    return saldoImpostoPagar;
  }
  
  public Valor getImpostoRestituir ()
  {
    return impostoRestituir;
  }
  
  public Valor getRendRecebidoExterior ()
  {
    return rendRecebidoExterior;
  }
  
  public abstract void resumoRendimentosTributaveis ();
  
  public abstract void resumoCalculoImposto ();
  
  public abstract void resumoOutrasInformacoes ();
  
  public abstract void aplicaValoresNaDeclaracao ();
  
  public abstract Valor recuperarTotalRendimentosTributaveis ();
  
  public abstract Valor recuperarTotalImpostoPago ();
  
  public String recuperarCodInImpostoAntecipado ()
  {
    String string = "0";
    if (! declaracaoIRPF.getResumo ().getCalculoImposto ().getImpostoRetidoFonteTitular ().isVazio () || ! declaracaoIRPF.getResumo ().getCalculoImposto ().getImpostoRetidoFonteDependentes ().isVazio () || ! declaracaoIRPF.getResumo ().getCalculoImposto ().getImpostoComplementar ().isVazio () || ! declaracaoIRPF.getResumo ().getCalculoImposto ().getCarneLeao ().isVazio () || ! declaracaoIRPF.getResumo ().getCalculoImposto ().getImpostoRetidoFonteLei11033 ().isVazio ())
      string = "1";
    return string;
  }
  
  public abstract String recuperarCodInImpostoPago ();
  
  public Valor getImpostoDevidoII ()
  {
    return impostoDevidoII;
  }
}
