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

// Java classes
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Map;

import org.apache.commons.lang.Validate;

// Library classes

// Framework classes
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.ServiceException;


// EDB classes
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.lookup.MeansTestStatus;
import gov.va.med.esr.common.model.financials.IncomeTestStatus;
import gov.va.med.esr.common.model.lookup.IncomeTestType;
import gov.va.med.esr.common.persistent.history.HistoryDAO;
import gov.va.med.esr.common.rule.service.EventRuleService;
import gov.va.med.esr.service.ClinicalDeterminationService;



/**
 * Project: Common
 * 
 * @author DNS   LEV
 * @version 1.0
 */
public class ClinicalDeterminationServiceImpl extends AbstractHistoricalInfoServiceImpl implements ClinicalDeterminationService {

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 6807451026344643378L;
    
	/**
	 * HistoryDAO for the retired CD data that retrieves the history data.
	 */
	private HistoryDAO         retiredCDHistoryDAO                    = null;

	/**
	 * 
	 */
	public ClinicalDeterminationServiceImpl() {
		super();
	}
	
    /**
	 * @see gov.va.med.esr.service.ClinicalDeterminationService#processCdForCleanup(gov.va.med.esr.common.model.person.id.PersonEntityKey)
	 */
	public Person processCdForCleanup(PersonEntityKey key) throws ServiceException {
		 Validate.notNull(key, "A veteran key must not be null");		
		Person person = this.getPersonService().getPerson(key);
	    
		// Handle the future Mt and secondary Rx income tests
		adjustFutureAndSecondaryTestsWithCd(person);
		
		// Handle the tests that are current and have applicable statuses
		this.getEnrollmentRuleService().calculateEE(person, true, false);

		// Handle post events
		EventRuleService eventRuleService = this.getEventRuleService();
		eventRuleService.manageMessageEvents(person);
		//call handbookrule ccr11159
		eventRuleService.manageHandBookEvents(person);
		
		// Persist the person
		return this.getPersonService().save(person);
	}

	private void adjustFutureAndSecondaryTestsWithCd(Person person) throws ServiceException {
		IncomeTest current = this.getHelperService().getCurrentIncomeTest(person);
		if (current != null && current.getType() != null) {
			// The following guard is to make sure only cases with Cd are affected
			Boolean cdIndicator = (person.getCatastrophicDisability() != null) ?
					person.getCatastrophicDisability().isCatastrophicallyDisabled() : null;

			if (cdIndicator == null || !cdIndicator.booleanValue()) {
				// don't adjust if it does not have CD
				return;
			}
			
			// REQ: If there is a Current Primary Means Test that is changed to NLR, 
			// update the associated Pharmacy Co-Pay Status to “No Longer Applies” (NLA)
			// Note that if it gets here, the current test status will be getting changed
			// later so need to adjust secondary now.
			if (IncomeTestType.CODE_MEANS_TEST.getCode().equals(current.getType().getCode())) {
				IncomeTestStatus incomeTestStatus = current.getPharmacyCoPayStatus();
				if (incomeTestStatus != null && incomeTestStatus.getType() != null && 
						IncomeTestType.CODE_CO_PAY_EXEMPTION_TEST.getCode().equals(
								incomeTestStatus.getType().getCode())) {
					incomeTestStatus.setStatus(this.getLookupService().getMeansTestStatusByCode(
							MeansTestStatus.MT_STATUS_NP_LONGER_APPLICABLE_RX_COPAY_ONLY.getName()));			        		 
				}
			}
		
			// Handle changing MT Status for cases where a future test(s) exist. 
			// Other cases should be handled by rules in E&E.
			Map incomeTests = person.getIncomeTests();

			// Get a list of all the income years for the tests
			List incomeYears = new ArrayList(incomeTests.keySet());
			if ((incomeYears == null) || (incomeYears.isEmpty())) {
				return;
			}

			// Loop through the income years from the most current to the oldest one
			Collections.sort(incomeYears);
			for (int i = incomeYears.size() - 1; i >= 0; i--) {
				// Get an income test
				Integer incomeYear = (Integer) incomeYears.get(i);
				// Get the income test
				IncomeTest incomeTest = (IncomeTest) incomeTests.get(incomeYear);
				if (incomeTest.isFutureTest() != null && incomeTest.isFutureTest().booleanValue()) {
					MeansTestStatus meansTestStatus = incomeTest.getStatus();
					if (meansTestStatus != null &&
							!MeansTestStatus.MT_STATUS_NO_LONGER_REQUIRED.getName().equals(meansTestStatus.getCode()) &&
							!MeansTestStatus.MT_STATUS_NP_LONGER_APPLICABLE_RX_COPAY_ONLY.getName().equals(meansTestStatus.getCode())) {
						IncomeTestType type = incomeTest.getType();
						if (type != null && IncomeTestType.CODE_MEANS_TEST.getCode().equals(type.getCode())) {
							incomeTest.setMeansTestStatus(this.getLookupService().getMeansTestStatusByCode(
									MeansTestStatus.MT_STATUS_NO_LONGER_REQUIRED.getName()));			        		 
						}
						else
							if (type != null && IncomeTestType.CODE_CO_PAY_EXEMPTION_TEST.getCode().equals(type.getCode())) {
								incomeTest.setMeansTestStatus(this.getLookupService().getMeansTestStatusByCode(
										MeansTestStatus.MT_STATUS_NP_LONGER_APPLICABLE_RX_COPAY_ONLY.getName()));			        		 
							}
					}
				}
			}				

		}	
	}
	
	/**
     * @see gov.va.med.esr.service.ClinicalDeterminationService#getClinicalDeterminationHistoryByChangeTime(gov.va.med.esr.service.impl.ChangeEvent)
     */
    public HistoricalInfo getClinicalDeterminationHistoryByChangeTime(ChangeEvent event) throws ServiceException {
        try {
            return this.getHistoryDAO().getHistoryByChangeTime(event);
        } catch (DAOException e) {
            throw new ServiceException(e.getMessage(),e);
        }
    }

    /**
     * @see gov.va.med.esr.service.ClinicalDeterminationService#getClinicalDeterminationHistoryChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    public Set getClinicalDeterminationHistoryChangeTimes(EntityKey personID) throws ServiceException {
        try {
            return this.getHistoryDAO().getHistoryChangeTimes(personID);
        } catch (DAOException e) {
            throw new ServiceException(e.getMessage(),e);
        }    
    }
    
	/**
     * @see gov.va.med.esr.service.ClinicalDeterminationService#getRetiredCDHistoryByChangeTime(gov.va.med.esr.service.impl.ChangeEvent)
     */
    public HistoricalInfo getRetiredCDHistoryByChangeTime(ChangeEvent event) throws ServiceException {
        try {
            return this.getRetiredCDHistoryDAO().getHistoryByChangeTime(event);
        } catch (DAOException e) {
            throw new ServiceException(e.getMessage(),e);
        }
    }

    /**
     * @see gov.va.med.esr.service.ClinicalDeterminationService#getRetiredCDHistoryChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    public Set getRetiredCDHistoryChangeTimes(EntityKey personID) throws ServiceException {
        try {
            return this.getRetiredCDHistoryDAO().getHistoryChangeTimes(personID);
        } catch (DAOException e) {
            throw new ServiceException(e.getMessage(),e);
        }    
    }

	public HistoryDAO getRetiredCDHistoryDAO() {
		return retiredCDHistoryDAO;
	}

	public void setRetiredCDHistoryDAO(HistoryDAO retiredCDHistoryDAO) {
		this.retiredCDHistoryDAO = retiredCDHistoryDAO;
	}

}
