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

// Java classes

// Library classes

// Framework classes
import org.apache.commons.lang.Validate;


import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.validation.ValidationMessages;
import gov.va.med.fw.validation.ValidationServiceException;
import gov.va.med.fw.validation.ValidationFieldMessage;

// ESR classes
import gov.va.med.esr.common.model.lookup.AACIndicator;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.ee.EligibilityVerification;
import gov.va.med.esr.common.model.ee.EnrollmentOverride;
import gov.va.med.esr.common.model.ee.IncompetenceRuling;
import gov.va.med.esr.common.model.ee.MonetaryBenefit;
import gov.va.med.esr.common.model.ee.MonetaryBenefitAward;
import gov.va.med.esr.common.model.ee.ServiceConnectionAward;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.rule.data.PersonInputData;
import gov.va.med.esr.common.rule.service.EligibilityFactorRuleService;
import gov.va.med.esr.service.EEResultInfo;
import gov.va.med.esr.service.LookupService;

/**
 * Project: Common
 * @author DNS   LEV
 * @version 1.0
 */
public class EligibilityFactorRuleServiceImpl extends
        AbstractRuleValidationServiceAwareImpl implements
        EligibilityFactorRuleService {

    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = -314967322970039187L;

    public static final String DISABILITY_COMPENSATION_UNKNOWN_NOT_ALLOWED_KEY = "DISABILITY_COMPENSATION_UNKNOWN_NOT_ALLOWED";
    public static final String DISABILITY_COMPENSATION_FIELDNAME = "isReceivingCompensation";

    private String newVeteranRuleParameters = null;

    private String manageSpecialFactorsRuleParameters = null;

    private String processSpecialFactorsRuleParameters = null;

    private LookupService lookupService;

    /**
     *
     */
    public EligibilityFactorRuleServiceImpl() {
        super();
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processMonetaryBenefitAward(gov.va.med.esr.common.model.ee.MonetaryBenefitAward,
     *      gov.va.med.esr.common.model.person.Person)
     */
    public void processMonetaryBenefitAward(MonetaryBenefitAward mb,
            Person onFile) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        if (mb != null) {
            MonetaryBenefitAward monetaryBenefitAward = onFile
                    .getMonetaryBenefitAward();
            if (monetaryBenefitAward == null) {
                monetaryBenefitAward = new MonetaryBenefitAward();
                onFile.setMonetaryBenefitAward(monetaryBenefitAward);
            }
            this.getMergeRuleService().mergeMonetaryBenefitAward(mb,
                    monetaryBenefitAward);
        } else {
            onFile.setMonetaryBenefitAward(null);
        }
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#manageMonetaryBenefitAward(gov.va.med.esr.common.model.ee.MonetaryBenefitAward, gov.va.med.esr.common.model.person.Person)
     */
    public void manageMonetaryBenefitAward(MonetaryBenefitAward mb, Person onFile) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        if (mb != null) {
            validateMonetaryBenefit(mb, onFile); //only for ui
            MonetaryBenefitAward monetaryBenefitAward = onFile
                    .getMonetaryBenefitAward();
            if (monetaryBenefitAward == null) {
                monetaryBenefitAward = new MonetaryBenefitAward();
                //CCR11262
                monetaryBenefitAward.setPerson(onFile);
                onFile.setMonetaryBenefitAward(monetaryBenefitAward);
            }
            this.getMergeRuleService().mergeMonetaryBenefitAward(mb,
                    monetaryBenefitAward);
        } else {
            onFile.setMonetaryBenefitAward(null);
        }
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processServiceConnectionAward(gov.va.med.esr.common.model.ee.ServiceConnectionAward,
     *      gov.va.med.esr.common.model.person.Person)
     */
    public void processServiceConnectionAward(ServiceConnectionAward sc,
            Person onFile) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        if (sc != null) {
            ServiceConnectionAward serviceConnectionAward = onFile
                    .getServiceConnectionAward();
            if (serviceConnectionAward == null) {
                serviceConnectionAward = new ServiceConnectionAward();
                onFile.setServiceConnectionAward(serviceConnectionAward);
            }
            this.getMergeRuleService().mergeServiceConnectionAward(sc,
                    serviceConnectionAward);
        } else {
            onFile.setServiceConnectionAward(null);
        }
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#manageSpecialFactors(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
     */
    public void manageSpecialFactors(Person incoming, Person onFile) throws ServiceException {
        this.doProcessSpecialFactor(incoming, null, onFile, true);
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processSpecialFactors(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
     */
    public void processSpecialFactors(Person incoming, VAFacility sendingFacility, Person onFile, boolean isUpdateFromGUI) throws ServiceException {
        this.doProcessSpecialFactor(incoming, sendingFacility, onFile, isUpdateFromGUI); //added sendingFacility so isMessageFromVoa will work
    }



    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#manageEligibilityVerification(gov.va.med.esr.common.model.ee.EligibilityVerification, gov.va.med.esr.common.model.person.Person)
     */
    public void manageEligibilityVerification(EligibilityVerification incoming, Person onFile) throws ServiceException {
        this.doProcessEligibilityVerification(incoming, onFile, true);
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processEligibilityVerification(gov.va.med.esr.common.model.ee.EligibilityVerification,
     *      gov.va.med.esr.common.model.person.Person)
     */
    public void processEligibilityVerification(EligibilityVerification incoming, Person onFile) throws ServiceException {
        this.doProcessEligibilityVerification(incoming, onFile, false);
    }

    private void doProcessEligibilityVerification(EligibilityVerification incoming, Person onFile, boolean isUpdateFromGUI) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        if (incoming != null) {
            EligibilityVerification eligibilityVerification = onFile.getEligibilityVerification();
            if (eligibilityVerification == null) {
                eligibilityVerification = new EligibilityVerification();
                onFile.setEligibilityVerification(eligibilityVerification);
            }
            this.getMergeRuleService().mergeEligibilityVerification(incoming, eligibilityVerification);

            // Reqt 3991 in the Manage Eligibility and Enrollment Use to set AACIndicator
            if (isUpdateFromGUI) {
                Person pristine = this.getPristinePerson(onFile);
                EligibilityVerification pristineEligibilityVerification = pristine != null ?
                        pristine.getEligibilityVerification() : null;

                String pristineStatusCode = (pristineEligibilityVerification != null &&
                        pristineEligibilityVerification.getEligibilityStatus() != null) ?
                            pristineEligibilityVerification.getEligibilityStatus().getCode() : null;

                String statusCode = incoming.getEligibilityStatus() != null ?
                        incoming.getEligibilityStatus().getCode() : null;

                if (statusCode != null && !statusCode.equals(pristineStatusCode)) {
                        eligibilityVerification.setAacIndicator(
                                this.getLookupService().getAACIndicatorByCode(AACIndicator.CODE_DATA_ACCEPTED.getCode()));
                }
            }
        } else {
            onFile.setEligibilityVerification(null);
        }
    }

    /**
     *
     *
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processIncompetenceRuling(gov.va.med.esr.common.model.ee.IncompetenceRuling,
     *      gov.va.med.esr.common.model.person.Person)
     */
    public void processIncompetenceRuling(IncompetenceRuling incoming,
            Person onFile) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        this.getMergeRuleService().mergeIncompetenceRuling(incoming, onFile);
    }



    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#manageEnrollmentOverride(gov.va.med.esr.common.model.ee.EnrollmentOverride, gov.va.med.esr.common.model.person.Person)
     */
    public void manageEnrollmentOverride(EnrollmentOverride incoming, Person onFile) throws ServiceException {
        Validate.notNull(onFile, "An onFile person must not be null ");

        if (incoming != null) {
            Person pristine = this.getPristinePerson(onFile);
            ValidationMessages messages = this.getRuleValidationService().validateReceivedEnrollment(incoming.getPerson(),onFile,pristine,true);

		    if( messages != null && !messages.isEmpty() ) {
		        throw new ValidationServiceException( messages );
		    }

            EnrollmentOverride enrollmentOverride= onFile.getEnrollmentOverride();
            if (enrollmentOverride == null) {
                enrollmentOverride = new EnrollmentOverride();
                onFile.setEnrollmentOverride(enrollmentOverride);
            }
            this.getMergeRuleService().mergeEnrollmentOverride(incoming, enrollmentOverride);
        } else {
            onFile.setEnrollmentOverride(null);
        }
    }


	/**
	 * CCR 10892 Add a Person
	 * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#manageNewVeteranFromAddPerson(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
	 */
	public void manageNewVeteranFromAddPerson(Person incoming, Person onFile) throws ServiceException {
		doProcessNewVeteran(incoming, onFile, true);
	}

	/**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processNewVeteran(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
     */
    public void processNewVeteran(Person incoming, Person onFile) throws ServiceException {
        doProcessNewVeteran(incoming, onFile, false);
    }

    /**
     * @see gov.va.med.esr.common.rule.service.EligibilityFactorRuleService#processEmergencyResponseIndicator(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
     */
    public void processEmergencyResponseIndicator(Person incoming, Person onFile) throws ServiceException {
        Validate.notNull(incoming, "An incoming person must not be null ");
        Validate.notNull(onFile, "An onFile person must not be null ");
        this.getMergeRuleService().mergeEmergencyResponseIndicator(incoming, onFile);
    }

    /**
     * @see gov.va.med.esr.common.rule.service.impl.AbstractRuleValidationServiceAwareImpl#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();

        Validate.notNull( this.newVeteranRuleParameters, "newVeteranRuleParameters property is required");
        Validate.notNull( this.manageSpecialFactorsRuleParameters, "manageSpecialFactorsRuleParameters property is required");
        Validate.notNull( this.processSpecialFactorsRuleParameters, "processSpecialFactorsRuleParameters property is required");
    }

    /**
     * @return Returns the newVeteranRuleParameters.
     */
    public String getNewVeteranRuleParameters() {
        return newVeteranRuleParameters;
    }

    /**
     * @param newVeteranRuleParameters The newVeteranRuleParameters to set.
     */
    public void setNewVeteranRuleParameters(String newVeteranRuleParameters) {
        this.newVeteranRuleParameters = newVeteranRuleParameters;
    }



    /**
     * @return Returns the manageSpecialFactorsRuleParameters.
     */
    public String getManageSpecialFactorsRuleParameters() {
        return manageSpecialFactorsRuleParameters;
    }

    /**
     * @param manageSpecialFactorsRuleParameters The manageSpecialFactorsRuleParameters to set.
     */
    public void setManageSpecialFactorsRuleParameters(
          String manageSpecialFactorsRuleParameters) {
        this.manageSpecialFactorsRuleParameters = manageSpecialFactorsRuleParameters;
    }

    /**
     * @return Returns the processSpecialFactorsRuleParameters.
     */
    public String getProcessSpecialFactorsRuleParameters() {
        return processSpecialFactorsRuleParameters;
    }

    /**
     * @param processSpecialFactorsRuleParameters The processSpecialFactorsRuleParameters to set.
     */
    public void setProcessSpecialFactorsRuleParameters(
          String processSpecialFactorsRuleParameters) {
        this.processSpecialFactorsRuleParameters = processSpecialFactorsRuleParameters;
    }


    private void doProcessNewVeteran(Person incoming, Person onFile, boolean isAddPerson) throws ServiceException {
        Validate.notNull(incoming, "An incoming person must not be null ");
        Validate.notNull(onFile, "An on file person must not be null ");

        Person pristine = this.getPristinePerson(onFile);

        // We using onFile as incoming person since we must examine eligibility status. Then
        // we update the eligibility status on same onFile.
        PersonInputData data = new PersonInputData(incoming, onFile, pristine);
        data.setFromAddNewPerson(isAddPerson);
        //CCR12710
        if (logger.isDebugEnabled()) {
	          logger.debug("EligFactorRuleSvc doProcNewVet : incoming: " + incoming + " onfile: " + onFile);
	    }

        this.invokeRuleFlow( this.getRuleParameters( this.getNewVeteranRuleParameters() ), data);
    }

    //added sendingFacility so isMessageFromVoa will work
    private void doProcessSpecialFactor(Person incoming, VAFacility sendingFacility, Person onFile, boolean isUpdateFromGUI ) throws ServiceException {
        Validate.notNull(onFile, "An on file person must not be null ");

        Person pristine = this.getPristinePerson(onFile);

        PersonInputData data = new PersonInputData(incoming, onFile, pristine, sendingFacility, isUpdateFromGUI);

        //CCR12710
        if (logger.isDebugEnabled()) {
	          logger.debug("EligFactorRuleSvc doProcSpecFactor : incoming: " + incoming + " onfile: " + onFile);
	    }

        if (isUpdateFromGUI) {
            this.invokeRuleFlow( this.getRuleParameters(this.getManageSpecialFactorsRuleParameters()), data);
        }
        else {
            this.invokeRuleFlow( this.getRuleParameters(this.getProcessSpecialFactorsRuleParameters()), data);
        }

    }

    // 228571 Added for DSLogon Level 2 process failure
    @Override
       public void processSpecialFactors(Person incoming,
                     VAFacility sendingFacility, Person onFile, boolean isUpdateFromGUI,
                     EEResultInfo clvInfo) throws ServiceException {
        this.doProcessSpecialFactor(incoming, sendingFacility, onFile, isUpdateFromGUI, clvInfo);
       }


   //added sendingFacility so isMessageFromVoa will work - user transient clvData
    private void doProcessSpecialFactor(Person incoming, VAFacility sendingFacility, Person onFile, boolean isUpdateFromGUI, EEResultInfo clvInfo ) throws ServiceException {
        Validate.notNull(onFile, "An on file person must not be null ");

        Person pristine = this.getPristinePerson(onFile);

        PersonInputData data = new PersonInputData(incoming, onFile, pristine, sendingFacility, isUpdateFromGUI);
        data.setEEResultInfo(clvInfo);

        if (logger.isDebugEnabled()) {
                 logger.debug("EligFactorRuleSvc doProcSpecFactor : incoming: " + incoming + " onfile: " + onFile);
           }

        if (isUpdateFromGUI) {
            this.invokeRuleFlow( this.getRuleParameters(this.getManageSpecialFactorsRuleParameters()), data);
        }
        else {
            this.invokeRuleFlow( this.getRuleParameters(this.getProcessSpecialFactorsRuleParameters()), data);
        }

    }


    public void validateMonetaryBenefit(MonetaryBenefitAward incomingMBA, Person onFile) throws ValidationServiceException {
        Validate.notNull(onFile, "An on-file Person must not be null.");
        boolean error = false;
        boolean incomingIsUnknown = false;

        if (incomingMBA != null) {
            MonetaryBenefit incomingDC = incomingMBA.getDisabilityCompensation();
            if (incomingDC != null && incomingDC.getMonetaryBenefitIndicator() != null
                    && incomingDC.getMonetaryBenefitIndicator().getCode().equals(Indicator.UNKOWN.getCode())) {
                incomingIsUnknown = true;
            }
        }

        if (incomingIsUnknown) {
            MonetaryBenefitAward  onfileMBA = onFile.getMonetaryBenefitAward();
            MonetaryBenefit onfileDC = (onfileMBA != null) ? onfileMBA.getDisabilityCompensation() : null;
            if (onfileDC == null || (onfileDC.getMonetaryBenefitIndicator() != null
                    && !onfileDC.getMonetaryBenefitIndicator().getCode()
                    .equals(Indicator.UNKOWN.getCode()))) {
                error = true;
            }
        }

        if (error) {
            ValidationMessages validationMessages = new ValidationMessages();
            validationMessages.add(new ValidationFieldMessage(DISABILITY_COMPENSATION_FIELDNAME,
                    DISABILITY_COMPENSATION_UNKNOWN_NOT_ALLOWED_KEY));
            throw new ValidationServiceException(validationMessages);
        }
    }

    /**
     * @return Returns the lookupService.
     */
    public LookupService getLookupService() {
        return lookupService;
    }

    /**
     * @param lookupService The lookupService to set.
     */
    public void setLookupService(LookupService lookupService) {
        this.lookupService = lookupService;
    }


}