package com.fitbank.installment;

import java.math.BigDecimal;

import com.fitbank.common.helper.Constant;
import com.fitbank.fin.helper.FinancialHelper;
import com.fitbank.hb.persistence.gene.Tcurrencyid;

/**
 * Clase que genera tabla de de pagos gradual con intereses anticipados.   
 * @author BANTEC Inc. 
 * @version 2.0 
 */
public class AdvancedInterestGradual extends AbstractQuota{

	/** Valor de cuota fija ajustada.  */
	private BigDecimal fixquota = Constant.BD_ZERO;
	/** Indica si se realizo o no el ajuste de una cuota fija. */
	/**Diferencia de la primera cuota, se utiliza para hcer ajustes a la cuota fija.*/
	private BigDecimal remainder = Constant.BD_ZERO;

	
	/* (non-Javadoc)
	 * @see com.fitbank.installment.AbstractQuota#calculate(com.fitbank.installment.InstallmentTable)
	 */
	public void calculate(InstallmentTable pQuotaTable) throws Exception {
		quotaTable = pQuotaTable;
		reducedcapital = quotaTable.getAmount();
		quotanumber = pQuotaTable.getBegincalculationperiod();
		isAdvancedInterest = true;
		//calcula el valor de cuota fija a pagar. 
		calculateFixedQuota();                         
		processCuotas();
	}
	  
	/**
	 * Metodo que genera la tabla de pagos desde la ultima cuota hasta la primera. 
	 * @throws Exception
	 */
	private void processCuotas() throws Exception {
		this.calculatePaymentDays();
		boolean first = true;
		boolean end = false;
		reducedcapital = Constant.BD_ZERO;
		for (int i = quotanumber; i >= quotaTable.getBegincalculationperiod(); i--) {			
			//calcula intereses, comiones,seguros para la cuota.
			if(i == quotaTable.getBegincalculationperiod() ){
				end = true;
			}
			this.calculateCuota(first,end,i);
			super.processByCategory(quotaTable.isCalculatePresentValue());
			first = false;
			if(super.stop){
				break;
			}
		}//end for	 
		//super.updateQuota(quotaTable.getBegincalculationperiod(), reducedcapital, Constant.BD_ZERO);
		super.updateQuota(0, reducedcapital, Constant.BD_ZERO);
		if(this.adjustQuote()){
			processCuotas();
		}
	}
	

	
	/**
	 * Calcula valor de capital a asociar a la cuota, adicion ala cuota a la tabla de pagos.
	 * @throws Exception
	 */
	private void calculateCuota(boolean pFirst,boolean pEnd,Integer pQuotaNumber) throws Exception{
		BigDecimal capital  = Constant.BD_ZERO;
		// Si se trata de la ultima cuota
		if(pFirst){
			// Define el valor de Intereses mas Comisiones de la cuota por si hay un residuo en la ultima cuota
			//  Carga todo el capital reducido al capital de la cuota
			capital = this.fixquota;						
		} else if(!pEnd){
			// Obtiene el valor de capital de la cuota
			capital = this.fixquota.subtract(this.globalIntrest);           
		}
		if(pEnd){
			capital = quotaTable.getAmount().subtract(reducedcapital);  
			remainder = capital.subtract(this.fixquota.subtract(this.globalIntrest));
		}
		this.reducedcapital = this.reducedcapital.add(capital);
		if(reducedcapital.compareTo(quotaTable.getAmount()) > 0){
			reducedcapital = quotaTable.getAmount();
		}
		super.updateQuota(pQuotaNumber, reducedcapital.subtract(capital), capital);
		super.globalIntrest = Constant.BD_ZERO;
	}
	
	/**
	 * Calcula la fecha de pago de cada una de las cuotas, sin incluir el detalle de la cuota con el calculo de intereses. 
	 * @throws Exception
	 */
	private void calculatePaymentDays() throws Exception {
		int size = quotaTable.getTotalperiod() ;
		size = size + quotaTable.getBegincalculationperiod()-1;
		super.addOnePayMetDay(quotaTable);
		super.addQuota(0,this.reducedcapital,Constant.BD_ZERO,false);
		//quotanumber++;
		super.removeOnePayMetDay(quotaTable);
		for (int i = quotaTable.getBegincalculationperiod(); i <= size; i++) {
			super.globalIntrest = Constant.BD_ZERO;
			super.calculatePayDate(quotaTable);
			super.addQuota(this.quotanumber,this.reducedcapital,Constant.BD_ZERO,true);
			quotanumber++;
		}//end for
		quotanumber--;
	}
	
	
	/**
	 * Si el valor de la ultima cuota es diferente del valor de la cuota fija, se obtiene un 
	 * nuevo valor de cuota fija con aproimaciones sucesivas. 
	 * @throws Exception
	 */
	private boolean adjustQuote()throws Exception{	
		if(remainder.compareTo(Constant.BD_ZERO) <= 0){
			return false;
		}
		Tcurrencyid  tcurrencyid = FinancialHelper.getInstance().getTcurrencyid(this.quotaTable.getCurrency());
		BigDecimal adjust = remainder.divide( new BigDecimal(quotaTable.getTotalperiod()),
				tcurrencyid.getNumerodecimales(),BigDecimal.ROUND_HALF_UP); 				
		if(adjust.compareTo(Constant.BD_ONE_HUNDREDTH) <= 0){
			return false;
		}
		BigDecimal quotavalue = fixquota.add(adjust);
		quotaTable.setFixquota(quotavalue);
		quotaTable.getQuotasBean().clear();
		quotaTable.getQuotaCategoryBean().clear();
		super.setPreviouspaydate(null);
		super.setNextpaydate(null);
		this.fixquota = quotavalue;
		quotanumber = quotaTable.getBegincalculationperiod();
		mCategoryRates = null;
		return true;
		
	}
	
	/**
	 * Metodo que calcula el valor de la cuota fiaja con interes anticipado. 
	 * @throws Exception
	 */
	private void calculateFixedQuota() throws Exception {
		super.interestFrquencyDays = quotaTable.getDaysperperiod();
		FixedInstallment fi = new FixedInstallment(quotaTable.getCalculationBase());
		fixquota = fi.calculateIA(reducedcapital, quotaTable.getTotalrate(), quotaTable.getDaysperperiod(), quotaTable.getTotalperiod(),
				quotaTable.getCurrency());
	    
	}
	
}//end class 
