package com.fp.general.rules.save;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import com.fp.common.helper.CalculationBase;
import com.fp.dto.rules.TransactionRule;
import com.fp.dto.save.SaveRequest;
import com.fp.general.exception.GeneralException;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.db.DataHelper;
import com.fp.persistence.commondb.helper.APPDates;
import com.fp.persistence.pgeneral.date.TgeneAccountingDate;
import com.fp.persistence.pgeneral.date.TgeneAccountingDateBranch;
import com.fp.persistence.pgeneral.date.TgeneAccountingDateKey;

/**
 * Calse que se encarga de cambiar la fecha contable de la aplicacion. 
 * @author Jorge Vaca.
 * @version 2.1
 *
 */
public class ChangeAccountingDate extends TransactionRule{

	/* (non-Javadoc)
	 * @see com.fp.dto.rules.TransactionRule#normalProcess(com.fp.dto.save.SaveRequest)
	 */
	public SaveRequest normalProcess(SaveRequest pSaveRequest) throws Exception {
		TgeneAccountingDateBranch ad = DataHelper.getInstance().getTgeneAccountingDateBranch(pSaveRequest.getCompany(), 0);
		//Fecha contable anterior 
		this.fillPrevious(ad);
		APPDates d = new APPDates(ad.getRealdate(),CalculationBase.B365365);
		boolean aux = true;
		while (aux) {
			aux = this.fillAccountingdate(ad, pSaveRequest.getCompany(), d);
		}
		//Proxima Fecha contable
		this.fillNext(ad, d,  pSaveRequest.getCompany());
		PersistenceHelper.saveOrUpdate(ad);
		this.fillResponse(pSaveRequest, ad);
		return pSaveRequest;
	}
	
	/**
	 * Fija la fecha contable anterior. 
	 * @param ad  Objeto que contiene los datos actuales de la fecha contable.
	 * @throws Exception
	 */
	private void fillPrevious(TgeneAccountingDateBranch ad) throws Exception {
		if(ad.getRealdate().compareTo(ad.getAccountingdate()) < 0){
			ad.setPreviousaccountingdate(ad.getPreviousaccountingdate());	
		}else{
			ad.setPreviousaccountingdate(ad.getAccountingdate());
		}		
	}
	
	/**
	 * Fija la proxima fecha cobtable.
	 * @param ad  Objeto que contiene la proxima fecha contable.
	 * @param d  Rerefencia al objeto AppDates
	 * @param pCompany  Codigo de compania.
	 * @throws Exception
	 */
	private void fillNext(TgeneAccountingDateBranch ad,APPDates d,Integer pCompany) throws Exception {
		d = new APPDates(ad.getAccountingdate(),CalculationBase.B365365);
		d.addField(Calendar.DAY_OF_YEAR, 1);
		TgeneAccountingDate cal = this.getTgeneAccountingDate(0, pCompany, d.getDate());
		ad.setNextaccountingdate(cal.getAccountingdate());
	}
	
	/**
	 * Metodo que fija la fecha contable. 
	 * @param ad  Objeto que contiene la proxima fecha contable.
	 * @param pCompany  Codigo de compania.
	 * @param d  Rerefencia al objeto AppDates
	 * @return  boolean
	 * @throws Exception
	 */
	private boolean fillAccountingdate(TgeneAccountingDateBranch ad,Integer pCompany,APPDates d ) throws Exception {
		boolean aux = true;
		d.addField(Calendar.DAY_OF_YEAR, 1);
		TgeneAccountingDate cal = this.getTgeneAccountingDate(0, pCompany, d.getDate());		
		ad.setAccountingdate(cal.getAccountingdate());
		ad.setWorkingdate(cal.getWorkingdate());
		ad.setRealdate(cal.getPk().getRealdate());
		if(ad.getWorkingdate().compareTo(ad.getAccountingdate()) == 0 ){
			if(ad.getWorkingdate().compareTo(ad.getRealdate()) == 0){
				aux = false;	
			}			
		}else{
			aux = false;
		}
		//
		return aux;
	}
	
	private TgeneAccountingDate getTgeneAccountingDate(Integer pBranch, Integer pCompany,Date pDate) throws Exception {
		TgeneAccountingDateKey key = new  TgeneAccountingDateKey(0,pCompany,pDate);
		TgeneAccountingDate cal = TgeneAccountingDate.find(PersistenceHelper.getEntityManager(), key);
		if(cal == null){
			SimpleDateFormat fd = new SimpleDateFormat("dd-MM-yyyy");
			throw new GeneralException("GENE-0024","CALENDARIO NO DEFINIDO EN TGENEACCOUNTINGDATE PARA LA FECHA: {0} ", fd.format(pDate));
		}
		return cal;
	}
	
	/**
	 * Arma la respuesta con las fechas resultanrtes.
	 * @param pSaveRequest  Datos del request original.
	 * @param ad  Objeto que contiene la proxima fecha contable.
	 * @throws Exception
	 */
	private void fillResponse(SaveRequest pSaveRequest,TgeneAccountingDateBranch ad) throws Exception {
		Map<String, Date> m = new  HashMap<String, Date>();
		m.put("realdate", ad.getRealdate());
		m.put("workdate", ad.getWorkingdate());
		m.put("accodate", ad.getAccountingdate());
		pSaveRequest.getResponse().put("NEXTDATE", m);
	}
	/* (non-Javadoc)
	 * @see com.fp.dto.rules.TransactionRule#reverseProcess(com.fp.dto.save.SaveRequest)
	 */
	public SaveRequest reverseProcess(SaveRequest pSaveRequest) throws Exception {
		// No tiene reverso
		return pSaveRequest;
	}

	
}
