package com.fitbank.installment;

import java.math.BigDecimal;
import java.sql.Date;

import com.fitbank.common.ApplicationDates;
import com.fitbank.common.Helper;
import com.fitbank.common.exception.FitbankException;
import com.fitbank.common.helper.Constant;
import com.fitbank.fin.helper.FinancialHelper;
import com.fitbank.hb.persistence.acco.Taccount;
import com.fitbank.hb.persistence.acco.TaccountKey;
import com.fitbank.hb.persistence.gene.Tcurrencyid;
import com.fitbank.hb.persistence.gene.Tfrecuencyid;

/**
 * Clase que se encarga de generar tabla de amortizacion con cuota fija de capital, interes al vencimiento. 
 * @author BANTEC Inc.
 * @version 2.0
 */
public class CapitalfixInstallment extends AbstractQuota{
  
	 /**
     * Numero de cuota de capital.
     */
    protected int totalCapitalPeriod = 0;
    /**
     * Periodos con capital.
     */
    protected int capitalPeriod = 0;
    /**
     * Numero de cuota de interes.
     */
    protected int totalInterestPeriod = 0;
    protected Date originalInicialDate;

    protected BigDecimal quotaCapital;

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.fitbank.installment.AbstractQuota#calculate(com.fitbank.installment
     * .InstallmentTable)
     */
    public void calculate(InstallmentTable pQuotaTable) throws Exception {
        this.quotaTable = pQuotaTable;
        this.quotanumber = pQuotaTable.getBegincalculationperiod();
        this.reducedcapital = pQuotaTable.getAmount();
        this.generateGrace();
        this.generateTable();
    }

    /**
     * Genera cuotas de interes por el numero de periodos de gracia definidos
     * para la tabla.
     * 
     * @throws Exception
     */
    private void generateGrace() throws Exception {
        if (quotaTable.getGraceperiod() > 0) {
            for (int i = 0; i < quotaTable.getGraceperiod(); i++) {
                super.calculatePayDate(quotaTable);
                super.processByCategory(false);
                super.addQuota(quotanumber, reducedcapital, Constant.BD_ZERO,
                        true);
                quotanumber++;
            }
        }
    }
    /**
     * Método que genera la tabla de amortización.
     * 
     * @throws Exception
     */
    private void generateTable() throws Exception {
        // Genera las cuotas de capital e interes
        boolean end = false;
        this.fillCapitalQuotas();
        int capitalQuotaCounter = 0;
        originalInicialDate = quotaTable.getFirstpaymetdate();
        Integer counter=quotanumber;
        for (int i = counter; i <= totalInterestPeriod; i++) {
            capitalQuotaCounter = capitalQuotaCounter + 1;
            super.calculatePayDate(this.quotaTable);
            if (i == totalInterestPeriod) {
                end = true;
            }
            super.processByCategory(false);
            this.calculateCuota(quotaCapital, end);
            capitalQuotaCounter = 0;
            this.quotanumber++;
        }// end for
    }

    /**
     * Metodo que valida frecuencias de capital sea un multiplo de la frecuencia
     * de interes, obtiene el valor de capital a cobrar en cada cuota que
     * coinsida con la frecuencia de capital.
     * 
     * @throws Exception
     */
    protected void fillCapitalQuotas() throws Exception {
        // Obtiene la moneda de la tabla de pagos
        Tcurrencyid tcurrencyid = FinancialHelper.getInstance().getTcurrencyid(
                this.quotaTable.getCurrency());
        // Define el total de cuotas de capital de la tabla de pagos
        Tfrecuencyid capitalFrequencyId = FinancialHelper.getInstance()
                .getTfrecuencyid(quotaTable.getCapitalFrequency());
        if (this.quotaTable.getAccountnumber() != null) {
            TaccountKey key = new TaccountKey(
                    this.quotaTable.getAccountnumber(),
                    ApplicationDates.DEFAULT_EXPIRY_TIMESTAMP,
                    this.quotaTable.getCompany());
            Taccount taccount = (Taccount) Helper.getBean(Taccount.class, key);
            if (taccount != null) {
                    this.totalCapitalPeriod = this.quotaTable.getTotalperiod();
            }
        } else {
                this.totalCapitalPeriod = this.quotaTable.getTotalperiod();
        }
        // Define el total de cuotas de interes de la tabla de pagos
        Tfrecuencyid interestFrequencyId = FinancialHelper.getInstance()
                .getTfrecuencyid(quotaTable.getIntrestFrequency());
        if (interestFrequencyId.getNumerodias().compareTo(
                capitalFrequencyId.getNumerodias()) > 0) {
            throw new FitbankException("QUO010",
                    "FRECUENCIA DE INTERES TIENE QUE SER MENOR O IGUAL A LA FRECUENCIA DE CAPITAL.");
        }
        if (capitalFrequencyId.getNumerodias()
                % interestFrequencyId.getNumerodias() != 0) {
            throw new FitbankException("QUO011",
                    "FRECUENCIA DE CAPITAL TIENE QUE SER MULTIPLO DE LA FRECUENCIA DE INTERES.");
        }
        super.interestFrquencyDays = interestFrequencyId.getNumerodias();
        if (interestFrequencyId != null
                && interestFrequencyId.getNumerodias() != null) {
            this.totalInterestPeriod = this.quotaTable.getTerm()
                    / interestFrequencyId.getNumerodias();
        } else {
            this.totalInterestPeriod = this.quotaTable.getTotalperiod();
        }
        if (capitalFrequencyId.getNumerodias().compareTo(
                interestFrequencyId.getNumerodias()) > 0) {
            this.capitalPeriod = capitalFrequencyId.getNumerodias()
                    / interestFrequencyId.getNumerodias();
        } else {
            this.capitalPeriod = 1;
        }
        // Obtiene el valor fijo de capital de cada cuota
        quotaCapital = this.quotaTable.getAmount().divide(
                new BigDecimal(this.totalCapitalPeriod-this.quotaTable.getGraceperiod()),
                tcurrencyid.getNumerodecimales(), BigDecimal.ROUND_HALF_UP);
    }

    /**
     * Calcula tabla de pago dado una cuota fija.
     * 
     * @throws Exception
     */
    private void calculateCuota(BigDecimal pCapital, boolean pEnd)
            throws Exception {
        // Obtiene los valores de interes y comision para cada categoria
        // Obtiene el valor de interes y comision de la cuota
        // Si se trata de la ultima cuota
        BigDecimal capital = pCapital;
        if (pEnd) {
            // Carga todo el capital reducido al capital de la cuota
            capital = this.reducedcapital;
        }
        super.addQuota(this.quotanumber, this.reducedcapital, capital, true);
        if (!pEnd) {
            if (capital.compareTo(this.reducedcapital) > 0) {
                capital = this.reducedcapital;
            }
            this.reducedcapital = this.reducedcapital.subtract(capital);
        }
    }
  
}
