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

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

import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.rule.RuleDataAware;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.DateUtils;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.rule.RuleException;

import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.model.lookup.EmploymentStatus;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.Employment;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.Spouse;
import gov.va.med.esr.common.rule.EmploymentInput;
import gov.va.med.esr.common.rule.service.MatchRuleService;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.service.external.demographics.DemographicsChangeEvent;

/**
 * This class expects that an employment will be provided in the incoming position.
 * 
 * @author Wen Lin created this class
 * @version 1.0
 */
public class EmploymentInputParameter extends BaseParameter implements EmploymentInput {

/**
    * An instance of serialVersionUID
    */

	private static final long serialVersionUID = -1613498691937118670L;

/**
    * A default constructor
    */
   public EmploymentInputParameter() {
      super();
   }
   
   // employment methods need to be in Spouse also
   	public Employment getEmployment()
	{
	    return this.getEmployment(this.getIncomingPerson());
	}
	public Employment getResultEmployment(){
		return this.getEmployment(this.getResultPerson());
	}
	public Employment getPristineEmployment()
	{
	    return this.getEmployment(this.getPristinePerson());
	}
	private Employment getEmployment(Person person) {
		return person != null ? person.getEmployment() : null;
	}
	
	public String getEmployerName() 
	{
		return this.getEmployerName(this.getEmployment());
	}
	public String getPristineEmployerName() 
	{
		return this.getEmployerName(this.getPristineEmployment());
	}
	public String getEmployerName(Employment employment){
		return employment!=null ? employment.getEmployerName():null;
	}
	
	public EmploymentStatus getEmploymentStatus() 
	{
		return this.getEmploymentStatus(this.getEmployment());
	}
	public EmploymentStatus getPristineEmploymentStatus() 
	{
		return this.getEmploymentStatus(this.getPristineEmployment());
	}
	public EmploymentStatus getEmploymentStatus(Employment employment){
		return employment!=null ? employment.getEmploymentStatus():null;
	}
	
	public Address getEmployerAddress() 
	{
		return this.getEmployerAddress(this.getEmployment());
	}
	public Address getPristineEmployerAddress() 
	{
		return this.getEmployerAddress(this.getPristineEmployment());
	}
	public Address getEmployerAddress(Employment employment){
		return employment!=null ? employment.getEmployerAddress():null;
	}
	
	// CCR 10673
	public ImpreciseDate getRetirementDate(){
		return this.getRetirementDate(this.getEmployment());
	}
	public ImpreciseDate getPristineRetirementDate(){
		return this.getRetirementDate(this.getPristineEmployment());
	}
	public ImpreciseDate getRetirementDate(Employment employment){
		return employment!=null ? employment.getRetirementDate(): null;
	}	
	public String getEmployerPhone(){
		return this.getEmployerPhone(this.getEmployment());
	}
	public String getPristineEmployerPhone(){
		return this.getEmployerPhone(this.getPristineEmployment());
	}
	public String getEmployerPhone(Employment employment){
		return employment!=null ? employment.getEmployerPhone(): null;
	}
	
	public String getEmployerAddressLineTwo(){
		return this.getEmployerAddressLineTwo(this.getEmployment());
	}
	public String getEmployerAddressLineTwo(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getLine2(): null;
		}
		return null;
	}
	
	public String getEmployerAddressLineThree(){
		return this.getEmployerAddressLineThree(this.getEmployment());
	}
	public String getEmployerAddressLineThree(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getLine3(): null;
		}
		return null;
	}
	
	public String getEmployerCity(){
		return this.getEmployerCity(this.getEmployment());
	}
	public String getEmployerCity(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getCity(): null;
		}
		return null;
	}
	
	public String getEmployerState(){
		return this.getEmployerState(this.getEmployment());
	}
	public String getEmployerState(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getState(): null;
		}
		return null;
	}
	
	public String getEmployerZipCode(){
		return this.getEmployerZipCode(this.getEmployment());
	}
	public String getEmployerZipCode(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getZipCode(): null;
		}
		return null;
	}
	
	public String getEmployerZipPlus4(){
		return this.getEmployerZipPlus4(this.getEmployment());
	}
	public String getEmployerZipPlus4(Employment employment){
		if ( employment!=null ) {
			Address address = employment.getEmployerAddress();
			return address!=null ? address.getZipPlus4(): null;
		}
		return null;
	}

	// setter
	public void setEmployerAddressLineTwo(Employment resultEmployment, Employment incomingEmployment){
	//	Employment resultEmployment = this.getResultPerson().getEmployment();
	//	Employment incomingEmployment = this.getIncomingPerson().getEmployment();
	//		 CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null)
					  resultAddress = new Address();
				  resultAddress.setLine2(incomingAddress.getLine2());
			  }
		}
	}

	public void setEmployerAddressLineThree(Employment resultEmployment, Employment incomingEmployment){
		// Employment resultEmployment = this.getResultPerson().getEmployment();
		// Employment incomingEmployment = this.getIncomingPerson().getEmployment();
		
		// CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null)
					  resultAddress = new Address();
				  resultAddress.setLine3(incomingAddress.getLine3());
			  }
		}
	}
	
	public void setEmployerCity(Employment resultEmployment, Employment incomingEmployment){
		// Employment resultEmployment = this.getResultPerson().getEmployment();
		// Employment incomingEmployment = this.getIncomingPerson().getEmployment();
		//	   CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null )
					  resultAddress = new Address();
				  resultAddress.setCity(incomingAddress.getCity());
			  }
		}
	}
	
	public void setEmployerState(Employment resultEmployment, Employment incomingEmployment){
		// Employment resultEmployment = this.getResultPerson().getEmployment();
		// Employment incomingEmployment = this.getIncomingPerson().getEmployment();
		
		//	   CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null)
					  resultAddress = new Address();
				  resultAddress.setState(incomingAddress.getState());
			  }
		}
	}
	
	public void setEmployerZipCode(Employment resultEmployment, Employment incomingEmployment){
		// Employment resultEmployment = this.getResultPerson().getEmployment();
		// Employment incomingEmployment = this.getIncomingPerson().getEmployment();
		
		//	   CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null)
					  resultAddress = new Address();
				  resultAddress.setZipCode(incomingAddress.getZipCode());
			  }
		}
	}
	
	public void setEmployerZipPlus4(Employment resultEmployment, Employment incomingEmployment){
	//	Employment resultEmployment = this.getResultPerson().getEmployment();
	//	Employment incomingEmployment = this.getIncomingPerson().getEmployment();
		
	    //   CCR10081 -- add guards against Null Pointer Exception
		if(incomingEmployment != null && resultEmployment != null) {
			  Address incomingAddress = incomingEmployment.getEmployerAddress();
			  Address resultAddress = resultEmployment.getEmployerAddress();
			  if (incomingAddress !=null){
				  if ( resultAddress == null)
					  resultAddress = new Address();
				  resultAddress.setZipPlus4(incomingAddress.getZipPlus4());
			  }
		}
	}
	
	public void setEmployerPhone(Employment resultEmployment, Employment incomingEmployment){
	//	Employment incomingEmployment = this.getIncomingPerson().getEmployment();
	//	Employment resultEmployment = this.getResultPerson().getEmployment();
		if(incomingEmployment != null) {
			if (resultEmployment == null)
				resultEmployment = new Employment();
			resultEmployment.setEmployerPhone(incomingEmployment.getEmployerPhone());
		}
	}
  public void setOccupation(Employment resultEmployment, Employment incomingEmployment){
         if(incomingEmployment != null) {
                if (resultEmployment == null)
                    resultEmployment = new Employment();
                resultEmployment.setOccupation(incomingEmployment.getOccupation());
            }
        }
      
     
	public void setEmployerAddress(Employment incomingEmployment,Employment resultEmployment){
	//	Employment incomingEmployment = this.getEmployment();
	//	Employment resultEmployment = this.getResultEmployment();
		if(incomingEmployment != null) {
			if (resultEmployment == null)
				resultEmployment = new Employment();
			resultEmployment.setEmployerAddress(incomingEmployment.getEmployerAddress());
		}
	}
   
	
	public void setEmployerName(Employment resultEmployment, Employment incomingEmployment){
	//	Employment incomingEmployment = this.getEmployment();
	//	Employment resultEmployment = this.getResultEmployment();;
		if(incomingEmployment != null) {
			if (resultEmployment == null)
				resultEmployment = new Employment();
			resultEmployment.setEmployerName(incomingEmployment.getEmployerName());
		}
	}

	// new methods of employment for VOA 3.1
	public void removeEmployment(Employment employment) {
     //   Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	employment.setEmployerName(null);
        	employment.setEmployerAddress(null);
        	employment.setEmployerPhone(null);
            employment.setRetirementDate(null);
        }
	}
	public void removeEmployment() {
       Employment employment = this.getResultEmployment();
       removeEmployment(employment);
	}
	
	public void removeEmployerAddressLineTwo(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setLine2(null);
        }
	}
	
	/**
	 * @see gov.va.med.esr.common.rule.EmploymentInput#removeEmployerAddressLineOne(gov.va.med.esr.common.model.person.Employment)
	 */
	public void removeEmployerAddressLineOne(Employment employment) {
		// CCR 10535 - Spouse Employment is broken
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setLine1(null);
        }
	}

	public void removeEmployerAddressLineTwo(){
		Employment employment = this.getResultEmployment();
		removeEmployerAddressLineTwo(employment);
	}
	
	public void removeEmployerAddressLineThree(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setLine3(null);
        }
	}
	public void removeEmployerAddressLineThree(){
		Employment employment = this.getResultEmployment();
		removeEmployerAddressLineThree(employment);
	}
	
	public void removeEmployerCity(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setCity(null);
        }
	}
	public void removeEmployerCity(){
		Employment employment = this.getResultEmployment();
		removeEmployerCity(employment);
	}
	
	public void removeEmployerState(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setState(null);
        }
	}
	public void removeEmployerState(){
		Employment employment = this.getResultEmployment();
		removeEmployerState(employment);
	}
	
	public void removeEmployerZipCode(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setZipCode(null);
        }
	}
	public void removeEmployerZipCode(){
		Employment employment = this.getResultEmployment();
		removeEmployerZipCode(employment);
	}
	
	public void removeEmployerZipPlus4(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	Address address = employment.getEmployerAddress();
        	if (address !=null)
        		address.setZipPlus4(null);
        }
	}
	public void removeEmployerZipPlus4(){
		Employment employment = this.getResultEmployment();
		removeEmployerZipPlus4(employment);
	}
	
	public void removeEmployerPhone(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
        	employment.setEmployerPhone(null);
        }
	}
	public void removeEmployerPhone(){
		Employment employment = this.getResultEmployment();
		removeEmployerPhone(employment);
	}
	public void removeDateOfRetirement(Employment employment){
		// Employment employment = this.getResultEmployment();;
        if(employment != null) {
            employment.setRetirementDate(null);
        }
	}
	public void removeDateOfRetirement(){
		Employment employment = this.getResultEmployment();
        removeDateOfRetirement(employment);
	}

   public void updateEmployment() throws RuleException {

      Employment updated = this.getResultEmployment();
      Employment incoming = this.getEmployment();
      updateEmployment(updated,incoming);
   }
   
   public void updateEmployment(Employment updated, Employment incoming) throws RuleException {
	   //   Employment updated = this.getResultEmployment();
	   //   Employment incoming = this.getEmployment();
	      
	      if( updated != null && incoming != null ) {
	         try {
	            this.getMergeRuleService().mergeEmployment(incoming, updated);
	         }
	         catch( ServiceException e ) {
	            if( this.logger.isDebugEnabled() ) {
	               this.logger.debug("Failed to merge an employment "+ e);
	            }
	            throw new RuleException("Failed to merge an employment " +  e);
	         }
	      }
	   }
  
   public void acceptEmploymentForTheVeteran() {
      try {
         Employment incoming = this.getEmployment();
         Employment resultEmployment = null;
         if( this.isUpdateFromGUI() ) {
            resultEmployment = incoming!=null ? this.getResultPerson().getEmployment(): null;
         }
         else {
            resultEmployment = this.getResultEmployment();
         }
         if( resultEmployment != null ) {
            if( logger.isDebugEnabled() ) {
               logger.debug("Accept and merge employment " + incoming.toString());
            }
            this.getMergeRuleService().mergeEmployment(incoming, resultEmployment);
         }
         else {
             addNewEmployment();
         }
      }
      catch( ServiceException e ) {
         if( this.logger.isDebugEnabled() ) {
            this.logger.debug("Failed to merge an employment", e);
         }
         throw new RuntimeException("Failed to merge an employment", e);
      }
   }

   public void addNewEmployment() {
       try {
           if( logger.isDebugEnabled() ) {
               logger.debug("Accept and add a new employment "
                     + this.getEmployment().toString());
            }
             // create a new employment, merge and add
             Employment newEmployment = new Employment();
             this.getMergeRuleService().mergeEmployment(this.getEmployment(),newEmployment);
             this.getResultPerson().setEmployment(newEmployment);
       }
       catch( ServiceException e ) {
          if( this.logger.isDebugEnabled() ) {
             this.logger.debug("Failed to add an employment", e);
          }
          throw new RuntimeException("Failed to add an employment", e);
       }
    }
   
   // TODO for spouse
   public void acceptEmploymentForTheSpouse(Employment incoming, Employment resultEmployment) {
	      try {
	      //   Employment incoming = this.getEmployment();
	      //   Employment resultEmployment = null;
	         if( this.isUpdateFromGUI() ) {
	            resultEmployment = incoming!=null ? resultEmployment: null;
	         }
	         else {
	            resultEmployment = this.getResultEmployment();
	         }
	         if( resultEmployment != null ) {
	            if( logger.isDebugEnabled() ) {
	               logger.debug("Accept and merge employment " + incoming.toString());
	            }
	            this.getMergeRuleService().mergeEmployment(incoming, resultEmployment);
	         }
	         else {
	             addNewEmploymentForSpouse(incoming);
	         }
	      }
	      catch( ServiceException e ) {
	         if( this.logger.isDebugEnabled() ) {
	            this.logger.debug("Failed to merge an employment", e);
	         }
	         throw new RuntimeException("Failed to merge an employment", e);
	      }
	   }
   
   // TODO for spouse
   public void addNewEmploymentForSpouse(Employment incomingEmployment) {
       try {
           if( logger.isDebugEnabled() ) {
               logger.debug("Accept and add a new employment "
                     + this.getEmployment().toString());
            }
             // create a new employment, merge and add
             Employment newEmployment = new Employment();
             this.getMergeRuleService().mergeEmployment(incomingEmployment,newEmployment);
             // TODO TODO for spouse
             //           CCR10081 -- add guards against Null Pointer Exception
             Employment spouseEmployment = this.getResultPerson().getEmployment();
             if (spouseEmployment != null && spouseEmployment.getSpouse() != null)
               spouseEmployment.getSpouse().setEmployment(newEmployment);
       }
       catch( ServiceException e ) {
          if( this.logger.isDebugEnabled() ) {
             this.logger.debug("Failed to add an employment", e);
          }
          throw new RuntimeException("Failed to add an employment", e);
       }
    }
   
   public boolean isEmploymentStatusUnknownOrNotEmployed(){
	   	Employment incomingEmployment = this.getEmployment();
		return isEmploymentStatusUnknownOrNotEmployed(incomingEmployment);
	}
   
   // for spouse or spouse and veteran
   public boolean isEmploymentStatusUnknownOrNotEmployed(Employment incomingEmployment){
	 //  	Employment incomingEmployment = this.getEmployment();
	   	EmploymentStatus employmentStatus = null;
		if(incomingEmployment != null ) {
			employmentStatus = incomingEmployment.getEmploymentStatus();
		}
		
		if (employmentStatus == null) return true;
		
		if (employmentStatus!=null &&  ( EmploymentStatus.CODE_UNKNOWN.getCode().equalsIgnoreCase(employmentStatus.getCode())
				|| EmploymentStatus.CODE_NOT_EMPLOYED.getCode().equalsIgnoreCase(employmentStatus.getCode() ) ) ) 
			return true;
		else 
			return false;
   }
   
   public boolean isEmploymentAddressGroupAllNull(Employment incomingEmployment){
	   Address incomingaddress = null;
	   
	   if (incomingEmployment==null) return true;
	   
	   incomingaddress = incomingEmployment.getEmployerAddress();
	   if ( incomingaddress==null )
		   return true;
	   
	   if ( incomingaddress.getLine1()==null &&
			incomingaddress.getLine2()==null  && 
			incomingaddress.getLine3()==null &&
			incomingaddress.getCity()==null &&
			incomingaddress.getState()==null &&
			incomingaddress.getZipCode()==null ) 
		   return true;
	   else 
		   return false;	   
   }
   
   public boolean isEmployerNameNotEqualtoESREmployerName(Employment incomingEmployment, Employment pristineEmployment){
	//   Employment incomingEmployment = this.getEmployment();
	//   Employment pristineEmployment = this.getPristineEmployment();
	   String incomingEmployerName =null;
	   String pristineEmployerName = null;
	   
	   if (incomingEmployment==null || pristineEmployment == null)
		   return false;
	   if ( incomingEmployment!=null)
		   incomingEmployerName = incomingEmployment.getEmployerName();
	   if (pristineEmployment !=null )
		   pristineEmployerName = pristineEmployment.getEmployerName();
	   
	   
	   if (incomingEmployerName!=null && pristineEmployerName!=null && !incomingEmployerName.equalsIgnoreCase(pristineEmployerName))
		   return true;
	   else 
		   return false;
   }
   
   public void deleteEmployerAddressGroup(Employment resultEmployment){
	   Address employerAddress = null;
	   if (resultEmployment!=null){
		   employerAddress = resultEmployment.getEmployerAddress();
		   if (employerAddress!=null){
		   		employerAddress.setLine1(null);
		   		employerAddress.setLine2(null);
		   		employerAddress.setLine3(null);
		   		employerAddress.setCity(null);
		   		employerAddress.setState(null);
		   		employerAddress.setZipCode(null);
		   }
		   resultEmployment.setEmployerAddress(null);
	   }
   }
   
   public boolean isAddressLineTwoNull(Employment incomingEmployment){
	   Address employerAddress = null;
	   if (incomingEmployment!=null){
		   employerAddress = incomingEmployment.getEmployerAddress();
		   if ( employerAddress !=null)
			   return employerAddress.getLine2()==null;
		   else 
			   return false;
	   }
	   else 
		   return false;
   }

   public boolean isEmployerNameNotNull(Employment incomingEmployment){
	   String employerName = null;
	   if (incomingEmployment!=null){
		   employerName = incomingEmployment.getEmployerName();
		   return employerName!=null;
	   }
	   else 
		   return false;
   }

   public boolean isEmploymentStatusNotRetired(Employment incomingEmployment) {
		EmploymentStatus employmentStatus = null;
		if(incomingEmployment != null ) {
			employmentStatus = incomingEmployment.getEmploymentStatus();
		}
		if (employmentStatus!=null && !EmploymentStatus.CODE_RETIRED.getCode().equalsIgnoreCase(employmentStatus.getCode()) )  
			return true;
		else 
			return false;
   }

   /**
    * @see gov.va.med.esr.common.rule.EmploymentInput#getEmploymentStatusCode(gov.va.med.esr.common.model.person.Employment)
    */
   public String getEmploymentStatusCode(Employment employment) {
	   return (employment != null && employment.getEmploymentStatus() != null) ? 
			   employment.getEmploymentStatus().getCode() : null;
   }

   /**
    * @see gov.va.med.esr.common.rule.EmploymentInput#getEmployerAddressLineOne(gov.va.med.esr.common.model.person.Employment)
    */
   public String getEmployerAddressLineOne(Employment employment) {
		if (employment != null) {
			Address address = employment.getEmployerAddress();
			return address != null ? address.getLine1(): null;
		}
		return null;
   }

   public boolean isIncomingMessageHasOccupation(Employment incomingEmployment) {
	     // CCR10081 -- add guards against Null Pointer Exception
	   // CCR 10535 - Spouse Employment is broken
	   if (incomingEmployment != null  && 
			   !StringUtils.isBlank(incomingEmployment.getOccupation())){
		   return true;
	   }

	   return false;
	}
}