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

// Java classes
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

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.esr.common.batchprocess.SSASSNVerificationData;
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.ee.VerificationInfo;
import gov.va.med.esr.common.model.lookup.DeathDataSource;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.DeathRecord;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.Relation;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.rule.data.ExternalSystemsInputData;
import gov.va.med.esr.common.rule.data.PersonInputData;
import gov.va.med.esr.common.rule.data.SSNVerificationResponseInputData;
import gov.va.med.esr.common.rule.service.DemographicRuleService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.UnknownLookupCodeException;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.service.external.demographics.DemographicsChangeEvent;

/**
 * Project: Common
 *
 * @author DNS   LEV
 */
public class DemographicRuleServiceImpl extends AbstractRuleValidationServiceAwareImpl
      implements DemographicRuleService {

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

   private String manageDemographicRuleParameters = null;

   private String processDemographicRuleParameters = null;

   private String processExternalServicesRuleParameters = null;

   private String processSSNVerificationResponseRuleParameters = null;

   private String manageIdentityTraitsRuleParameters = null;

   private LookupService lookupService;

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

   /**
    * Updates demographic information. This method is meant to be called from UI.
    *
    * @param incoming
    *           person with the data updated by UI
    * @param onFile
    *           the person on file
    * @throws ServiceException
    *            thrown when there is application error or rule validation errors.
    */
   public Person manageDemographicInfo(Person incoming, Person onFile) throws ServiceException {
      Validate.notNull(incoming, "A veteran incoming must not be null");

      // Validate an incoming demographic information
      ValidationMessages messages = this.getRuleValidationService().validateDemographic(
            incoming, true);

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

      Person pristine = this.getPristinePerson(onFile);

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

      // Invoke process demographic rule flow
      invokeRuleFlow( this.getRuleParameters( this.getManageDemographicRuleParameters() ),
                      new PersonInputData( incoming, onFile, pristine, true));

      return onFile;
   }

   /**
    * Updates demographic information. This method is meant to be called from the
    * Messaging.
    *
    * @param incoming
    *           person with the data updated by Messaging.
    * @param onFile
    *           the person on file
    * @throws ServiceException
    *            thrown when there is application error or rule validation errors.
    */
   public void processDemographicInfo(VAFacility sendingFacility, Person incoming,
         Person onFile, boolean isDataFromGUI,String MVIActiveInd) throws ServiceException {

      Validate.notNull(onFile, "A veteran on file must not be null");
      Validate.notNull(incoming, "A veteran incoming must not be null");

      Person pristine = this.getPristinePerson(onFile);
      
      //overlay death record from onFile record to inocming record
      //if parameter is set for MVI death authority
      //i.e. ESR is to ignore vista death data if param is set
      //RTC WI 348581, filter sites by parameter list during MVI authority rollout
      if (MVIActiveInd.equalsIgnoreCase("Y")) {
    	  incoming.setDeathRecord(pristine.getDeathRecord());
      }


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

      // Invoke process demographic rule flow
      invokeRuleFlow( this.getRuleParameters( this.getProcessDemographicRuleParameters() ),
                      new PersonInputData( incoming, onFile, pristine, sendingFacility, isDataFromGUI));
   }
   
   /**
    * Updates demographic information. This method is meant to be called by
    * MVI processing.
    *
    * @param incoming
    *           person with the data updated by Messaging.
    * @param onFile
    *           the person on file
    * @throws ServiceException
    *            thrown when there is application error or rule validation errors.
    */
   public void processDemographicInfo(VAFacility sendingFacility, Person incoming,
         Person onFile, boolean isDataFromGUI, boolean isDataFromMVI) throws ServiceException {

      Validate.notNull(onFile, "A veteran on file must not be null");
      Validate.notNull(incoming, "A veteran incoming must not be null");

      Person pristine = this.getPristinePerson(onFile);

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

      // Invoke process demographic rule flow
      invokeRuleFlow( this.getRuleParameters( this.getProcessDemographicRuleParameters() ),
                      new PersonInputData( incoming, onFile, pristine, sendingFacility, isDataFromGUI, isDataFromMVI));
   }

   /**
    * @see gov.va.med.esr.common.rule.service.DemographicRuleService#processDemographicInfo(gov.va.med.esr.common.model.lookup.VAFacility,
    *      gov.va.med.esr.common.model.person.Person,
    *      gov.va.med.esr.common.model.person.Person,
    *      gov.va.med.esr.common.model.ee.VerificationInfo)
    */
   public void processDemographicInfo(VAFacility sendingFacility, Person incoming,
         Person onFile, VerificationInfo verificationInfo) throws ServiceException {
      Validate.notNull(onFile, "A veteran on file must not be null");
      Validate.notNull(incoming, "A veteran incoming must not be null");

      Person pristine = this.getPristinePerson(onFile);

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

      // Invoke process demographic rule flow
      invokeRuleFlow( this.getRuleParameters( this.getProcessDemographicRuleParameters() ),
                      new PersonInputData( incoming, onFile, pristine, sendingFacility, verificationInfo));
   }

   /**
    * @see gov.va.med.esr.common.rule.service.DemographicRuleService#processSocialSecurityInfo(java.util.Set,
    *      gov.va.med.esr.common.model.person.Person)
    */
   public void processSocialSecurityInfo(Set ssn, Person onFile) throws ServiceException {
      // TODO Auto-generated method stub

   }

   /**
    * @see gov.va.med.esr.common.rule.service.DemographicRuleService#manageIdentityTraits(gov.va.med.esr.common.model.person.Person, gov.va.med.esr.common.model.person.Person)
    */
   public void manageIdentityTraits(Person incoming, Person onFile) throws ServiceException {
       // Validate an incoming demographic information
       ValidationMessages messages = this.getRuleValidationService().validateIdentityTraits(incoming, true);

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

       Person pristine = this.getPristinePerson(onFile);

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

       // Invoke process demographic rule flow
       invokeRuleFlow( this.getRuleParameters( this.getManageIdentityTraitsRuleParameters() ),
                       new PersonInputData( incoming, onFile, pristine, true));
   }

   /**
    * @see gov.va.med.esr.common.rule.service.DemographicRuleService#processSocialSecurityInfo(gov.va.med.esr.common.model.person.SSN,
    *      gov.va.med.esr.common.model.person.Person)
    */
   public void processSocialSecurityInfo(SSN ssn, Person onFile) throws ServiceException {
      // TODO Auto-generated method stub

   }

   public void processSSNVerificationResponse(SSASSNVerificationData incoming,
         Person result, SSASSNVerificationData resultSSNVerificationData, Relation relation)
         throws ServiceException {
      Validate.notNull("Incoming SSASSNVerificationData cannot be null");

      Person pristine = result != null ? this.getPristinePerson(result) : null ;
      // The rule flow needs to trigger messages and bulletins which need the Person in
      // the result object. Create a SSNVerificationResponseInputData with Person as the
      // result parameter

      //CCR12710
      if (logger.isDebugEnabled()) {
          logger.debug("DemographicoRuleService processSSNResponse : incoming" + incoming + " person: " + result);
		}

      invokeRuleFlow( this.getRuleParameters( this.getProcessSSNVerificationResponseRuleParameters() ),
            new SSNVerificationResponseInputData(incoming, result, pristine,
                  resultSSNVerificationData,relation));
   }

   /**
    * @see gov.va.med.esr.common.rule.service.DemographicRuleService#processExternalDemographicChanges(java.util.Set,
    *      gov.va.med.esr.common.model.person.Person)
    */
   public void processExternalDemographicChanges(Set changes, Person onFile)
         throws ServiceException {
      Validate.notNull(onFile, "A veteran on file must not be null");
      for( Iterator i = changes.iterator(); i.hasNext(); ) {
         DemographicsChangeEvent demographicsChangeEvent = (DemographicsChangeEvent)i
               .next();
         ExternalSystemsInputData data = new ExternalSystemsInputData(onFile,
               demographicsChangeEvent);
         this.invokeRuleFlow( this.getRuleParameters( this.getProcessExternalServicesRuleParameters() ), data);
      }
   }


   public void attachDeathRecordFromIdm(Person incoming, Date dateOfDeath) throws ServiceException {
	   DeathRecord deathRecord = incoming.getDeathRecord();
	   if (deathRecord == null) {
		   deathRecord = new DeathRecord();
		   incoming.setDeathRecord(deathRecord);
	   }
	   incoming.getDeathRecord().setDeathDate(ImpreciseDateUtils.createImpreciseDateWithoutTime(dateOfDeath));
	   incoming.getDeathRecord().setDeathReportDate(this.getTransactionDate());
	   incoming.getDeathRecord().setLazarusDate(null);
	   incoming.getDeathRecord().setDataSource(
			   this.getLookupService().getDeathDataSourceByCode(
					   DeathDataSource.CODE_DEATH_CERT_ON_FILE.getCode()));
	   incoming.getDeathRecord().setFacilityReceived(
			   this.getLookupService().getVaFacilityByCode(VAFacility.CODE_HEC.getCode()));
   }

   /**
    * @see gov.va.med.esr.common.rule.service.impl.AbstractRuleValidationServiceAwareImpl#afterPropertiesSet()
    */
   public void afterPropertiesSet() throws Exception {
      super.afterPropertiesSet();
      Validate.notNull(this.manageDemographicRuleParameters,
            "manageDemographicRuleParameters property is required");
      Validate.notNull(this.processDemographicRuleParameters,
            "processDemographicRuleParameters property is required");
      Validate.notNull(this.processExternalServicesRuleParameters,
            "processExternalServicesRuleParameters property is required");
   }

   /**
    * @return Returns the demographicRuleParameters.
    */
   public String getManageDemographicRuleParameters() {
      return manageDemographicRuleParameters;
   }

   /**
    * @param demographicRuleParameters
    *           The demographicRuleParameters to set.
    */
   public void setManageDemographicRuleParameters(
         String manageDemographicRuleParameters) {
      this.manageDemographicRuleParameters = manageDemographicRuleParameters;
   }

   /**
    * @return Returns the demographicRuleParameters.
    */
   public String getProcessDemographicRuleParameters() {
      return processDemographicRuleParameters;
   }

   /**
    * @param demographicRuleParameters
    *           The demographicRuleParameters to set.
    */
   public void setProcessDemographicRuleParameters(
         String processDemographicRuleParameters) {
      this.processDemographicRuleParameters = processDemographicRuleParameters;
   }

   /**
    * @return Returns the processExternalServicesRuleParameters.
    */
   public String getProcessExternalServicesRuleParameters() {
      return processExternalServicesRuleParameters;
   }

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

   /**
    * @return Returns the processSSNVerificationResponseRuleParameters.
    */
   public String getProcessSSNVerificationResponseRuleParameters() {
      return processSSNVerificationResponseRuleParameters;
   }

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

   /**
    * @return Returns the manageIdentityTraitsRuleParameters.
    */
   public String getManageIdentityTraitsRuleParameters() {
       return manageIdentityTraitsRuleParameters;
   }

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

   public LookupService getLookupService() {
	   return lookupService;
   }

   public void setLookupService(LookupService lookupService) {
	   this.lookupService = lookupService;
   }
}