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

// Java Classes
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

// Library Classes
import org.apache.commons.lang.Validate;

// Framework Classes
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.trigger.TriggerRouter;
import gov.va.med.fw.validation.ValidationMessage;
import gov.va.med.fw.validation.ValidationMessages;
import gov.va.med.fw.validation.ValidationServiceException;

// ESR Classes
import gov.va.med.esr.common.model.comms.AacLetterRequest;
import gov.va.med.esr.common.model.financials.DependentFinancials;
import gov.va.med.esr.common.model.financials.FinancialStatement;
import gov.va.med.esr.common.model.financials.GMTThreshold;
import gov.va.med.esr.common.model.financials.InProcessFinancialInfo;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.financials.IncomeThreshold;
import gov.va.med.esr.common.model.financials.SpouseFinancials;
import gov.va.med.esr.common.model.lookup.MeansTestStatus;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SignatureImage;
import gov.va.med.esr.common.model.person.Spouse;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.persistent.history.FinancialsHistoryDAO;
import gov.va.med.esr.common.rule.service.impl.RuleValidationMessage;
import gov.va.med.esr.service.EEResultInfo;
import gov.va.med.esr.service.EligibilityEnrollmentService;
import gov.va.med.esr.service.FinancialsHelperService;
import gov.va.med.esr.service.FinancialsService;
import gov.va.med.esr.service.IVMFinancialInfo;
import gov.va.med.esr.service.MessagingService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.UnknownLookupCodeException;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.service.trigger.IncomeYearTriggerEvent;

/**
 * Project: Common
 * @author DNS   LEV
 * @version 1.0
 */
public class FinancialsServiceImpl extends AbstractHistoricalInfoServiceImpl implements FinancialsService {
    // An instance of serialVersionUID
    private static final long serialVersionUID = -6546285562247192047L;

	/**
	 * HistoryDAO that retrieves the financial assessment history data.
	 */
    private FinancialsHistoryDAO financialsHistoryDAO;

    /**
	 * HistoryDAO that retrieves the dependent history data.
	 */
    private FinancialsHistoryDAO dependentHistoryDAO;

    private FinancialsHelperService financialsHelperService = null;

    private MessagingService messagingService = null;

    private EligibilityEnrollmentService eligibilityEnrollmentService = null;

    private TriggerRouter triggerRouter = null;

    public FinancialsServiceImpl() {
        super();
    }

    /**
     * @see gov.va.med.esr.service.impl.AbstractRuleAwareServiceImpl#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        Validate.notNull( this.financialsHelperService, "FinancialsHelperService is required" );
        Validate.notNull( this.messagingService, "MessagingService is required" );
        Validate.notNull( this.triggerRouter, "TriggerRouter is required" );
        Validate.notNull( this.eligibilityEnrollmentService, "EligibilityEnrollmentService is required" );
    }

    /**
     * @return financials helper service
     */
    public FinancialsHelperService getFinancialsHelperService()
    {
        return financialsHelperService;
    }

    /**
     * @param financialsHelperService the financials helper service.
     */
    public void setFinancialsHelperService(FinancialsHelperService financialsHelperService)
    {
        this.financialsHelperService = financialsHelperService;
    }

	/**
	 * @return dependent history DAO
	 */
	public FinancialsHistoryDAO getDependentHistoryDAO() {
		return dependentHistoryDAO;
	}

	/**
	 * @param dependentHistoryDAO the dependent history DAO
	 */
	public void setDependentHistoryDAO(FinancialsHistoryDAO dependentHistoryDAO) {
		this.dependentHistoryDAO = dependentHistoryDAO;
	}

	/**
	 * @return financials history DAO
	 */
	public FinancialsHistoryDAO getFinancialsHistoryDAO() {
		return financialsHistoryDAO;
	}

	/**
	 * @param financialsHistoryDAO the financials history DAO
	 */
	public void setFinancialsHistoryDAO(FinancialsHistoryDAO financialsHistoryDAO) {
		this.financialsHistoryDAO = financialsHistoryDAO;
	}

    /**
     * @return Returns the messagingService.
     */
    public MessagingService getMessagingService() {
        return messagingService;
    }

    /**
     * @param messagingService The messagingService to set.
     */
    public void setMessagingService(MessagingService messagingService) {
        this.messagingService = messagingService;
    }

    /**
     * @return Returns the eligibilityEnrollmentService.
     */
    public EligibilityEnrollmentService getEligibilityEnrollmentService() {
        return eligibilityEnrollmentService;
    }

    /**
     * @param eligibilityEnrollmentService The eligibilityEnrollmentService to set.
     */
    public void setEligibilityEnrollmentService(
            EligibilityEnrollmentService eligibilityEnrollmentService) {
        this.eligibilityEnrollmentService = eligibilityEnrollmentService;
    }

    /**
     * @return Returns the triggerRouter.
     */
    public TriggerRouter getTriggerRouter() {
        return triggerRouter;
    }

    /**
     * @param triggerRouter The triggerRouter to set.
     */
    public void setTriggerRouter(TriggerRouter triggerRouter) {
        this.triggerRouter = triggerRouter;
    }


    public Person updateInProcess(Integer incomeYear, Person incoming) throws ServiceException {
    	return updateInProcess(incomeYear, incoming, true);
    }



    /**
     * Process Financial data from IVM Message
     *
     */
    public Person convertOrReverseESRIncomeTest(Person incoming, IVMFinancialInfo ivmFinancialInfo) throws ServiceException {
    	Validate.notNull(ivmFinancialInfo, "An IVM Financials Info object must not be null");
        Validate.notNull(incoming, "A veteran must not be null");

        PersonService personService = this.getPersonService();

        Person onFile = personService.getPerson(incoming.getPersonEntityKey());
        onFile = this.getFinancialInfoRuleService().processIVMFinancials(incoming, onFile, ivmFinancialInfo);
        // For letters from IVM, use review only = true to allow call to trigger auto letters
        getEligibilityEnrollmentService().assessEEImpact(onFile, true);
        getEventRuleService().processMessageEventsForIVM(onFile);
        this.getEventRuleService().manageHandBookEvents(onFile);

        //Delete in process data, if any since IVM test is now in effect
        onFile.setInProcessFinancial(ivmFinancialInfo.getIncomeYear(), null);

        // Notice we make separate call to letters since we set review only in E&E
        this.getCommunicationRuleService().triggerAutomaticLetters(onFile, ivmFinancialInfo);

        // Save the updated person
        return personService.save(onFile);
	}

	public IncomeTest findConversionBaseTest(IncomeTest incomeTest) throws ServiceException {
	   	try {
			return this.getFinancialsHistoryDAO().findConversionBaseTest(incomeTest);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

	public List getIncomeTestStatusesForIVMReversal(Serializable key) throws ServiceException {
	   	try {
			return this.getFinancialsHistoryDAO().getIncomeTestStatusesForIVMReversal(key);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

	/**
     * @return the updated person
     * @see gov.va.med.esr.service.FinancialsService#updateInProcess(java.lang.Integer, gov.va.med.esr.common.model.person.Person)
     */
    public Person updateInProcess(Integer incomeYear, Person incoming, boolean savePerson) throws ServiceException {
        Validate.notNull(incomeYear, "A income year must not be null");
        Validate.notNull(incoming, "Incoming Person must not be null");

        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        InProcessFinancialInfo inProcessFinancial = incoming.getInProcessFinancial(incomeYear);

        if (inProcessFinancial == null) { //delete if exists
            onFile.setInProcessFinancial(incomeYear, null);
        } else {
            validateFinancialsUpdate(incomeYear, onFile);

            InProcessFinancialInfo onFileInprocess = onFile.getInProcessFinancial(incomeYear);
            if (onFileInprocess != null) {
                onFileInprocess.setInProcessData(inProcessFinancial.getInProcessData());
            }
            else {
                onFileInprocess = new InProcessFinancialInfo();
                onFileInprocess.setIncomeYear(incomeYear);
                onFileInprocess.setInProcessData(inProcessFinancial.getInProcessData());
                onFile.setInProcessFinancial(incomeYear, onFileInprocess);
            }
        }

        if ( savePerson )
        {
        	return personService.save(onFile);
        }
        else
        {
        	return onFile;
        }
    }

    //CCR12575 - make it public
    public void validateFinancialsUpdate(Integer incomeYear, Person onFile) throws ServiceException {
        if (!canFinancialsBeAdded(incomeYear, onFile)
                && !canFinancialsBeUpdated(incomeYear, onFile))
        {
            ValidationMessages validationMessages = new ValidationMessages();
            validationMessages.add(new ValidationMessage(RuleValidationMessage.INCOME_TEST_CANNOT_BE_ADDED_OR_EDITED.getCode()));
            throw new ValidationServiceException(validationMessages);
        }
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#updateFinancialAssessment(java.lang.Integer, gov.va.med.esr.common.model.person.Person)
     */
    public Person updateFinancialAssessment(Integer incomeYear, Person incoming) throws ServiceException
    {
        PersonService personService = this.getPersonService();

        Person result = personService.getPerson(incoming.getPersonEntityKey());

        EEResultInfo info = new EEResultInfo();
        result = assessFinancialImpactImpl(incomeYear, incoming, result, info);

        getEligibilityEnrollmentService().assessEEImpact(result, false);

        getEventRuleService().handleCommonPostEvents(result, true, info.isZ10Sent());

        //Delete in process data, if any
        result.setInProcessFinancial(incomeYear, null);

        // Save the updated person
        return personService.save(result);
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#assessFinancialImpact(java.lang.Integer, gov.va.med.esr.common.model.person.Person)
     */
    public Person assessFinancialImpact(Integer incomeYear, Person incoming) throws ServiceException
    {
        return assessFinancialImpactImpl(incomeYear, incoming, null, null);
    }

    /**
     * Assess the financial impact on the person (i.e. review impact).
     * @param incomeYear the income year to assess
     * @param incoming the incoming person
     * @param result the on-file person who will be updated in this API.
     * @param info the E&E result information.
     * @return the update person with the assessment applied.
     * @throws ServiceException if any problems were encountered.
     * @see gov.va.med.esr.service.FinancialsService#assessFinancialImpact(java.lang.Integer, gov.va.med.esr.common.model.person.Person)
     */
    public Person assessFinancialImpactImpl(Integer incomeYear, Person incoming, Person result, EEResultInfo info) throws ServiceException
    {
        Validate.notNull(incomeYear, "A income year must not be null");
        Validate.notNull(incoming, "A veteran must not be null");
        PersonService personService = this.getPersonService();

        if (result == null)
        {
            result = personService.getPerson(incoming.getPersonEntityKey());
        }
        Person onFile = (Person)result.clone();

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        VAFacility hec = getHECFacility();

        // Update a veteran on file with financial information for the review impact functionality.
        result = this.getFinancialInfoRuleService().manageFinancialAssessment(incomeYear, hec, incoming, result, info);

        // Ensure that something changed on the entity as compared to the onFile entity.
        // This comparison needs to be done after the "review impact" data has been placed on the person
        // since the incoming person may not have any changes if the changes are realted to financial dependent
        // updates that already occurred in a different flow.
        ensureEntityChanged(result, onFile);

        // Return the updated person
        return result;
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#updateSpouseFinancials(Integer, gov.va.med.esr.common.model.financials.SpouseFinancials, gov.va.med.esr.common.model.person.Person)
     */
    public Person updateSpouseFinancials(Integer incomeYear, SpouseFinancials spouseFinancials, Person incoming)
            throws ServiceException {
        Validate.notNull(incomeYear, "An income year must not be null");
        Validate.notNull(incoming, "A veteran must not be null");

        validateInProcessFinancials(incomeYear, incoming);

        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        // Ensure that something changed on the incoming entity as compared to the onFile entity
        ensureEntityChanged(incoming, onFile);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        FinancialStatement stmt = incoming.getFinancialStatement(incomeYear);
        FinancialStatement onFileStmt = onFile.getFinancialStatement(incomeYear);

        //Check if the spouse financials is deleted by the user
        if (spouseFinancials.getEntityKey() != null
                && stmt.getSpouseFinancialsByEntityKey(spouseFinancials.getEntityKey()) == null) {
            onFileStmt.removeSpouseFinancials(spouseFinancials);
        } else {
            // Step 1: Update a veteran on file with dependent financials information.
            onFile = this.getFinancialInfoRuleService().manageSpouseInfo(
                    incomeYear, spouseFinancials, incoming, onFile);
        }

        // Need to handle possible triggering of 290 letter for SSN Verification status of Invalid
        this.getCommunicationRuleService().triggerAutomaticLetters(onFile, null, AacLetterRequest.SPOUSE_LETTER);

        // Save the updated person
        return personService.save(onFile);
    }

    /*
     * @see gov.va.med.esr.service.FinancialsService#activateSpouse(java.lang.Integer, gov.va.med.esr.common.model.financials.SpouseFinancials, gov.va.med.esr.common.model.person.Person)
     */
    public Person activateSpouse(Integer incomeYear, SpouseFinancials spouseFinancials, Person incoming)
    throws ServiceException {
        Validate.notNull(incomeYear, "An income year must not be null");
        Validate.notNull(spouseFinancials, "A spouse financials must not be null");
        Validate.notNull(incoming, "A veteran must not be null");

        validateInProcessFinancials(incomeYear, incoming);

        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        FinancialStatement onFileStmt = onFile.getFinancialStatement(incomeYear);

        SpouseFinancials onFileSpouseFinancials = onFileStmt.getSpouseFinancialsByEntityKey(spouseFinancials.getEntityKey());

        // Remove inactive date
        Spouse onFileSpouse = (onFileSpouseFinancials != null) ? onFileSpouseFinancials.getReportedOn() : null;
        if(onFileSpouse != null && onFileSpouse.getEndDate() != null) {
            onFileSpouse.setEndDate(null);
            // Save the updated person
            onFile = personService.save(onFile);
        }
        return onFile;
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#updateDependentFinancials(java.lang.Integer, gov.va.med.esr.common.model.financials.DependentFinancials, gov.va.med.esr.common.model.person.Person)
     */
    public Person updateDependentFinancials(Integer incomeYear,
            DependentFinancials dependentFinancials, Person incoming)
            throws ServiceException {
        Validate.notNull(incomeYear, "An income year must not be null");
        Validate.notNull(dependentFinancials,
                "A dependent financial must not be null");
        Validate.notNull(incoming, "A veteran must not be null");

        validateInProcessFinancials(incomeYear, incoming);

        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        // Ensure that something changed on the incoming entity as compared to the onFile entity
        ensureEntityChanged(incoming, onFile);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        FinancialStatement stmt = incoming.getFinancialStatement(incomeYear);
        FinancialStatement onFileStmt = onFile.getFinancialStatement(incomeYear);

        //Check if the dependent financials is deleted by the user
        if (dependentFinancials.getEntityKey() != null
                && stmt.getDependentFinancialsByEntityKey(dependentFinancials.getEntityKey()) == null) {
            onFileStmt.removeDependentFinancials(dependentFinancials);
        } else {
            // Step 1: Update a veteran on file with dependent financials information.
            onFile = this.getFinancialInfoRuleService().manageDependentFinancialInfo(
                    incomeYear, dependentFinancials, incoming, onFile);
        }

        // Need to handle possible triggering of 290 letter for SSN Verification status of Invalid
        this.getCommunicationRuleService().triggerAutomaticLetters(onFile, null, AacLetterRequest.DEPENDENT_LETTER);

        // Save the updated person
        return personService.save(onFile);
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#updateDependents(java.lang.Integer, gov.va.med.esr.common.model.person.Person)
     */
    public Person updateDependents(Integer incomeYear, Person incoming) throws ServiceException
    {
        // Validate the parameters
        Validate.notNull(incomeYear, "An income year must not be null");
        Validate.notNull(incoming, "A veteran must not be null");

        validateInProcessFinancials(incomeYear, incoming);

        // Get the on-file Person
        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        // No entity check is needed here since this is only called from "Copy Dependents" and "Delete".
        // Both of these flows will always be changing something.
        // ensureEntityChanged(incoming, onFile);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        // Get the passed in and on-file financial statements
        FinancialStatement stmt = incoming.getFinancialStatement(incomeYear);
        FinancialStatement onFileStmt = onFile.getFinancialStatement(incomeYear);

        if (stmt == null)
        {
            // If the incoming statement is null, delete the financial statement from the on-file person
            onFile.setFinancialStatement(incomeYear, null);
        }
        else
        {
            // If there is no current financial statement on file, add a new empty one
            if (onFileStmt == null)
            {
                onFileStmt = new FinancialStatement();
                onFileStmt.setIncomeYear(incomeYear);
                onFile.setFinancialStatement(incomeYear, onFileStmt);
            }

            // Merge the incoming financial statement information onto the on-file person
            this.getMergeRuleService().mergeFinancialStatement(stmt, onFileStmt);
        }

        // Save the updated person
        return getPersonService().save(onFile);
    }

    public Person updatePendingAdjudicationStatus(Integer incomeYear, Person incoming, MeansTestStatus status) throws ServiceException {
        Validate.notNull(incomeYear, "An income year must not be null");
        Validate.notNull(incoming, "A veteran must not be null");
        Validate.notNull(status, "A new MeansTestStatus must not be null");

        // Get the on-file Person
        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        Validate.notNull(onFile.getIncomeTest(incomeYear), "IncomeTest for adjudication can not be null");

        onFile = this.getFinancialInfoRuleService().managePendingAdjudicationStatus(incomeYear, incoming, onFile, status);

        this.getEligibilityEnrollmentService().assessEEImpact(onFile, false);

        getEventRuleService().handleCommonPostEvents(onFile, true);

        // Save the updated person
        return personService.save(onFile);
    }

    protected void validateInProcessFinancials(Integer incomeYear, Person incoming) throws ValidationServiceException
    {
        Validate.notNull(incoming, "Incoming Person must not be null.");
        if (incoming.getInProcessFinancial(incomeYear) != null)
        {
            ValidationMessages validationMessages = new ValidationMessages();
            validationMessages.add(new ValidationMessage(RuleValidationMessage.FINANCIALS_INPROCESS_STATE.getCode()));
            throw new ValidationServiceException(validationMessages);
        }
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#processFutureDatedTestFlag(gov.va.med.esr.common.model.person.id.PersonEntityKey, java.lang.Integer)
     */
    public Person processFutureDatedTestFlag(PersonEntityKey personKey, Integer incomeYear) throws ServiceException {
        Validate.notNull(personKey, "A PersonKey must not be null");
        Validate.notNull(incomeYear, "An income year must not be null");

        // Get the on-file Person
        PersonService personService = this.getPersonService();
        Person result = personService.getPerson(personKey);

        IncomeTest test = result.getIncomeTest(incomeYear);
        if (test != null && Boolean.TRUE.equals(test.getFutureTest())) {
            test.setFutureTest(Boolean.FALSE);

            this.getEnrollmentRuleService().calculateEEForExpireMTBatchJob(result, incomeYear);
            getEventRuleService().handleCommonPostEvents(result, false);

            if(logger.isDebugEnabled()) {
                logger.debug("Future Dated test effective. E&E executed.");
            }

            IncomeYearTriggerEvent incomeYearTriggerEvent = IncomeYearTriggerEvent.notifyVistaForFinancial(incomeYear);
            incomeYearTriggerEvent.setPersonId(personKey);
            incomeYearTriggerEvent.setIdentityTraits(result != null ? result.getIdentityTraits():null);
            getTriggerRouter().processTriggerEvent(incomeYearTriggerEvent);

            if(logger.isDebugEnabled()) {
                logger.debug("Future Dated test effective. Z10 triggered.");
            }
            // Save the updated person
            return personService.save(result);
        }
        return result;
    }

    /**
	 * @see gov.va.med.esr.service.FinancialsService#getGMTThreshold(java.lang.Integer, java.lang.String)
	 */
	public GMTThreshold getGMTThreshold(Integer incomeYear, String zipCode) throws ServiceException {
		return getGMTThreshold(incomeYear, zipCode, 0);
	}

	/**
	 * @see gov.va.med.esr.service.FinancialsService#getGMTThreshold(java.lang.Integer, java.lang.String, int)
	 */
	public GMTThreshold getGMTThreshold(Integer incomeYear, String zipCode, int extraDependents) throws ServiceException {
		String fipsCode = getLookupService().getFipsCode(zipCode);
		if (fipsCode == null) {
			throw new ServiceException("No fips code is located with a given zip code "+zipCode);
		}
		return getFinancialsHelperService().calculateGMTThresholds(incomeYear, fipsCode, extraDependents);
	}

	/**
	 * @see gov.va.med.esr.service.FinancialsService#getIncomeThreshold(java.lang.Integer)
	 */
	public IncomeThreshold getIncomeThreshold(Integer incomeYear) throws ServiceException {
		return getIncomeThreshold(incomeYear, 0);
	}

	/**
	 * @see gov.va.med.esr.service.FinancialsService#getIncomeThreshold(java.lang.Integer, int)
	 */
	public IncomeThreshold getIncomeThreshold(Integer incomeYear, int extraDependents) throws ServiceException {
		return getFinancialsHelperService().calculateIncomeThresholds(incomeYear, extraDependents);
	}

	/**
     * Checks if the a new Imcome test be added.
     */
    public boolean canFinancialsBeAdded(Integer incomeYear, Person person)
    throws ServiceException
    {
        if(	financialsHelperService.isAllowedtoAddMeansTest(person, incomeYear) ||
            financialsHelperService.isAllowedtoAddPharmacyCopayTest(person, incomeYear) ||
            financialsHelperService.isAllowedtoAddTest(person, incomeYear))
        {
            return true;
        }
        return false;
    }


    /**
     * Checks if the a new Imcome test be updated.
     */
    public boolean canFinancialsBeUpdated(Integer incomeYear, Person person)
    throws ServiceException
    {
        return financialsHelperService.isAllowedtoEditTest(person, incomeYear);
    }

    /**
     * Checks if the Net Worth information be updated.
     */
    public boolean canNetWorthBeUpdated(Integer incomeYear, Person person)
    throws ServiceException
    {
        return financialsHelperService.isAllowedtoEditNetWorth(person, incomeYear);
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#getHistoricalFeeBasisInfo(gov.va.med.fw.model.EntityKey)
     */
    public Person getHistoricalFeeBasisInfo(EntityKey key)
            throws ServiceException {
        return null;
    }

	/*
	 *
	 * @see gov.va.med.esr.service.FinancialsService#getFinancialAssessmentHistoryChangeTimes(gov.va.med.fw.model.EntityKey,
	 *      java.lang.Integer)
	 */
	public Set getFinancialAssessmentHistoryChangeTimes(
			EntityKey entityKey, Integer incomeYear)
			throws ServiceException {
	   	try {
			return financialsHistoryDAO.getHistoryChangeTimes(entityKey, incomeYear);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

	/*
	 *
	 * @see gov.va.med.esr.service.FinancialsService#getFinancialAssessmentHistoryByChangeTime(gov.va.med.esr.service.impl.FinancialsChangeEvent)
	 */
	public HistoricalInfo getFinancialAssessmentHistoryByChangeTime(FinancialsChangeEvent changeEvent)
			throws ServiceException {
	   	try {
			return financialsHistoryDAO.getHistoryByChangeTime(changeEvent);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

	/*
	 *
	 * @see gov.va.med.esr.service.FinancialsService#getDependentHistoryChangeTimes(gov.va.med.fw.model.EntityKey,
	 *      java.lang.Integer)
	 */
	public Set getDependentHistoryChangeTimes(EntityKey entityKey,
			Integer incomeYear) throws ServiceException {
	   	try {
			return dependentHistoryDAO.getHistoryChangeTimes(entityKey, incomeYear);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

	/*
	 *
	 * @see gov.va.med.esr.service.FinancialsService#getDependentHistoryByChangeTime(gov.va.med.esr.service.impl.FinancialsChangeEvent)
	 */
	public HistoricalInfo getDependentHistoryByChangeTime(
			FinancialsChangeEvent changeEvent) throws ServiceException {
	   	try {
			return dependentHistoryDAO.getHistoryByChangeTime(changeEvent);
		} catch (DAOException e) {
			throw new ServiceException(e.getMessage(),e);
		}
	}

    /**
     * @see gov.va.med.esr.service.FinancialsService#updatePersonSignature(gov.va.med.esr.common.model.person.Person)
     */
    public Person updatePersonSignature(Person incoming) throws ServiceException {
        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        // Ensure that something changed on the incoming entity as compared to the onFile entity
        ensureEntityChanged(incoming, onFile);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(onFile);

        Map dfns = this.getDfns(incoming, onFile);

        this.getFinancialInfoRuleService().managePersonSignatures(incoming.getSignatureImages(), onFile, dfns);
        return personService.save(onFile);
    }

    /**
     * @see gov.va.med.esr.service.FinancialsService#processPersonSignature(gov.va.med.esr.common.model.person.Person)
     */
    public Person processPersonSignature(Person incoming) throws ServiceException {
        PersonService personService = this.getPersonService();
        Person onFile = personService.getPerson(incoming.getPersonEntityKey());

        Map dfns = this.getDfns(incoming, onFile);

        this.getFinancialInfoRuleService().processPersonSignatures(incoming.getSignatureImages(), onFile, dfns);
        return personService.save(onFile);
    }


    private Map getDfns(Person incoming, Person onFile) throws ServiceException {
        Map dfns = new HashMap();
        Set images = incoming.getSignatureImages();
        for(Iterator iter = images.iterator(); iter.hasNext();) {
            SignatureImage si = (SignatureImage)iter.next();
            if (si.getSiteSubmittingImage() != null) {
                SiteIdentity siteIdentity = this.getMessagingService().getIdentity(onFile, si.getSiteSubmittingImage());
                if (siteIdentity != null && siteIdentity.getDfn() != null) {
                    dfns.put(si.getSiteSubmittingImage(), siteIdentity.getDfn());
                }
            }
        }
        return dfns;
    }

    private VAFacility getHECFacility() throws UnknownLookupTypeException, UnknownLookupCodeException {
        return getLookupService().getVaFacilityByCode(
                VAFacility.CODE_HEC.getName());
    }
}