/*******************************************************************************
 * Copyright © 2010 VHA. All rights reserved
 ******************************************************************************/
package gov.va.med.esr.service.impl;

import gov.va.med.esr.common.model.financials.RelaxationPercentage;
import gov.va.med.esr.common.persistent.financials.RelaxationPercentageDAO;
import gov.va.med.esr.common.persistent.history.HistoryDAO;
import gov.va.med.esr.service.RelaxationPercentageService;
import gov.va.med.fw.batchprocess.BatchProcessDetail;
import gov.va.med.fw.batchprocess.BatchProcessInvoker;
import gov.va.med.fw.batchprocess.BatchProcessService;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.scheduling.SchedulingService;
import gov.va.med.fw.security.LoginManager;
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.validation.ValidationMessage;
import gov.va.med.fw.validation.ValidationMessages;
import gov.va.med.fw.validation.ValidationServiceException;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;

/**
 * A service preconfigured with DAOs to query and update relaxation percentage
 * data.
 * 
 * @author DNS   barryc
 */
public  class RelaxationPercentageServiceImpl extends AbstractComponent
		implements RelaxationPercentageService {
	private static final long serialVersionUID = 6530216441579427869L;

	private static final String ERROR_MESSAGE_NEW_VAL_LESS_THAN_OLD = "errors.relaxationPercentage.newValueLessThanOldValue";
	private static final String ERROR_MESSAGE_NEW_VAL_LESS_THAN_CURRENT_INCOME_YEAR = "errors.relaxationPercentage.newValueLessThanCurrentYear";

	private RelaxationPercentageDAO relaxationPercentageDAO;
	private LoginManager loginManager;
	private HistoryDAO historyDAO = null;
	private BatchProcessInvoker invoker;
	private SchedulingService schedulingService;
	private BatchProcessService batchProcessService;
	
	public RelaxationPercentage getRelaxationPercentageByIncomeYear(
			int incomeYear) throws ServiceException {
		try {
			return relaxationPercentageDAO
					.getRelaxationPercentageByIncomeYear(incomeYear);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
	}

	public List getAllRelaxationPercentages() {
		return relaxationPercentageDAO.findAll();
	}

	public void addRelaxationPercentage(BigDecimal value)
			throws ServiceException {
		int currentYear = Calendar.getInstance().get(Calendar.YEAR);

		RelaxationPercentage rp = null;

		/*
		 * Ensure that we haven't already created a value for the current
		 * calendar year
		 */
		try {
			rp = relaxationPercentageDAO
					.getRelaxationPercentageByIncomeYear(currentYear);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
		if (rp != null)
			throw new ValidationServiceException("A "
					+ RelaxationPercentage.class.getName()
					+ " was already defined with the income year = "
					+ currentYear);

		/* Ensure that our new value isn't less than the current year's value */
		try {
			rp = relaxationPercentageDAO
					.getRelaxationPercentageByIncomeYear(currentYear - 1);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
		if (value.compareTo(rp.getValue()) == -1) {
			ValidationMessages validationMessages = new ValidationMessages();
			validationMessages.add(new ValidationMessage(
					ERROR_MESSAGE_NEW_VAL_LESS_THAN_CURRENT_INCOME_YEAR));
			throw new ValidationServiceException(validationMessages);
		}

		RelaxationPercentage newRp = new RelaxationPercentage(value,
				currentYear);
		try {
			relaxationPercentageDAO.saveObject(newRp);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
	}

	public void updateRelaxationPercentage(int incomeYear, BigDecimal value,
			boolean retroactiveProcess,BatchProcessDetail batchProcessDetail) throws ServiceException {
		RelaxationPercentage rp = null;
		try {
			rp = relaxationPercentageDAO
					.getRelaxationPercentageByIncomeYear(incomeYear);
		} catch (DAOException e) {
			throw new ServiceException(e);
		}
		if (rp == null)
			throw new ServiceException("No "
					+ RelaxationPercentage.class.getName()
					+ " was defined with the income year = " + incomeYear);

		if (value.compareTo(rp.getValue()) == -1) {
			ValidationMessages validationMessages = new ValidationMessages();
			validationMessages.add(new ValidationMessage(
					ERROR_MESSAGE_NEW_VAL_LESS_THAN_OLD));
			throw new ValidationServiceException(validationMessages);
		}

		for (int updateIncomeYear = incomeYear; rp != null
				&& updateIncomeYear < incomeYear + 50; updateIncomeYear++) {
			rp.setValue(value);
			try {
				relaxationPercentageDAO.saveObject(rp);
				rp = relaxationPercentageDAO
						.getRelaxationPercentageByIncomeYear(updateIncomeYear);
			} catch (DAOException e) {
				throw new ServiceException(e);
			}
		}

		if (retroactiveProcess) {
			String[] invocationArgs = {new Integer(incomeYear).toString()} ;
			invoker.invokeBatchProcessWithEvent(batchProcessDetail, invocationArgs);
		}
	}


	public Set getRelaxationPercentageHistoryChangeTimes()
			throws ServiceException {
		try {
			return historyDAO.getHistoryChangeTimes(null);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(), e);
		}
	}

	public HistoricalInfo getRelaxationPercentageHistoryByChangeTime(
			ChangeEvent event) throws ServiceException {
		try {
			return historyDAO.getHistoryByChangeTime(event);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(), e);
		}
	}

	/**
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull(relaxationPercentageDAO);
		Validate.notNull(loginManager);
		Validate.notNull(historyDAO);
	}

	public void setRelaxationPercentageDAO(
			RelaxationPercentageDAO relaxationPercentageDAO) {
		this.relaxationPercentageDAO = relaxationPercentageDAO;
	}

	public void setLoginManager(LoginManager loginManager) {
		this.loginManager = loginManager;
	}

	public void setHistoryDAO(HistoryDAO historyDAO) {
		this.historyDAO = historyDAO;
	}

	public BatchProcessService getBatchProcessService() {
		return batchProcessService;
	}

	public void setBatchProcessService(BatchProcessService batchProcessService) {
		this.batchProcessService = batchProcessService;
	}

	public BatchProcessInvoker getInvoker() {
		return invoker;
	}

	public void setInvoker(BatchProcessInvoker invoker) {
		this.invoker = invoker;
	}

	public SchedulingService getSchedulingService() {
		return schedulingService;
	}

	public void setSchedulingService(SchedulingService schedulingService) {
		this.schedulingService = schedulingService;
	}

}