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

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

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.EqualsBuilder;

// ESR Classes
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.ee.Document;
import gov.va.med.esr.common.model.ee.POWEpisode;
import gov.va.med.esr.common.model.ee.PrisonerOfWar;
import gov.va.med.esr.common.model.ee.PurpleHeart;
import gov.va.med.esr.common.model.ee.PurpleHeartDocument;
import gov.va.med.esr.common.model.ee.ReceivedEligibility;
import gov.va.med.esr.common.model.ee.SHADDocument;
import gov.va.med.esr.common.model.ee.SHAD;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.RegistryType;
import gov.va.med.esr.common.model.lookup.ReportExceptionType;
import gov.va.med.esr.common.model.person.DeathRecord;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.registry.Registry;
import gov.va.med.esr.common.model.registry.RegistryTrait;
import gov.va.med.esr.common.model.registry.RegistryTraitDetail;
import gov.va.med.esr.common.persistent.registry.RegistryDAO;
import gov.va.med.esr.common.rule.RegistryInput;
import gov.va.med.esr.common.rule.data.RegistryInputData;
import gov.va.med.esr.service.LoadRegistryResult;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.rule.RuleDataAware;
import gov.va.med.fw.rule.RuleException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

/**
 * Wraper class for the registry usecase.
 * 
 * @author Muddaiah Ranga
 * @version 3.0
 */
public class RegistryInputParameter extends BaseParameter implements RegistryInput {
    
    private static final long serialVersionUID = -2100826797626752705L;

    public boolean isEnrolled(Person person) {
        return (person != null) ? person.isEnrolled() : false;
    }
    
    public boolean isVeteran(Person person)  {
        return (person != null && person.isVeteran() != null) ? person.isVeteran().booleanValue() : false;
    }
    
    public String getReceivedPrimaryEligibilityCode(Person person) {
        ReceivedEligibility primary = (person != null) ? person.getReceivedPrimaryEligibility() : null;
        return (primary != null && primary.getType() != null) ? primary.getType().getCode() : null;
    }

    public boolean isNewRegistry() {
        Registry registry = this.getRegistry();
        return (registry != null && registry.getEntityKey() == null) ? true : false;
    }
    
    public boolean isRegistryExists() throws RuleException {
        try {
            Registry registry = this.getRegistry();
            RegistryTrait trait = registry.getRegistryTrait();
            RegistryTrait onFileTrait = this.getRegistryDAO().getRegistryTrait(registry);
            if((onFileTrait != null) && (trait.getEntityKey() == null || !trait.getEntityKey().equals(onFileTrait.getEntityKey())) ) {
                return true;
            }
        } catch(Exception ex) {
            throw new RuleException("Error while getting the registry trait",ex);
        }
        return false;
    }
    
    public String getRegistryType() {
      //  RegistryTrait trait = this.getRegistryTrait();
    	//return (trait != null && trait.getRegistryType() != null) ? trait.getRegistryType().getCode() : null;
    	RegistryType regType= getRegistryInputData().getRegistryTytpe();        
        return (regType != null) ? regType.getCode() : null;
    }
    
    public String getSSN() {
        return (this.getRegistryTrait() != null) ? this.getRegistryTrait().getSsn() : null;
    }
    
    public String getFirstName() {
        return (this.getRegistryTrait() != null) ? this.getRegistryTrait().getFirstName() : null;
    }

    public String getLastName() {
        return (this.getRegistryTrait() != null) ? this.getRegistryTrait().getLastName() : null;
    }

    public Date getDOD() {
        return (this.getRegistryTrait() != null && this.getRegistryTrait().getDeathDate() != null) ? ImpreciseDateUtils.getDateWithDefault(this.getRegistryTrait().getDeathDate()) : null;
    }
    
    /********************************** PH Getter/Setters **********************************************/
    
    public boolean getPHIndicator() {
        PurpleHeart ph = this.getPurpleHeart();
        return (ph != null && ph.getPhIndicator() != null) ?  ph.getPhIndicator().booleanValue() : false;
    }
    
    public boolean getPristinePHIndicator() {
        PurpleHeart ph = this.getPristinePurpleHeart();
        return (ph != null && ph.getPhIndicator() != null) ?  ph.getPhIndicator().booleanValue() : false;
    }
    
    public void setPHIndicator(boolean indicator) {
        PurpleHeart ph = this.getResultPurpleHeart();
        if(ph != null) {
            ph.setPhIndicator((indicator) ? Boolean.TRUE : Boolean.FALSE);
        }
    }

    public String getPHStatus() {
        PurpleHeart ph = this.getPurpleHeart();
        return (ph != null && ph.getStatus() != null) ? ph.getStatus().getCode() : null;
    }
    
    public String getPristinePHStatus() {
        PurpleHeart ph = this.getPristinePurpleHeart();
        return (ph != null && ph.getStatus() != null) ? ph.getStatus().getCode() : null;
    }
    
    public String getPHRejectedRemarks() {
        PurpleHeart ph = this.getPurpleHeart();
        return (ph != null && ph.getRejectionRemark() != null) ? ph.getRejectionRemark().getCode() : null;
    }

    public void setPHStatusUpdateDate(Date date) {
        PurpleHeart ph = this.getResultPurpleHeart();
        if(ph != null) ph.setStatusLastEditDate(date);
    }
    
    public void setPHStatusUpdateUser(String user) {
        PurpleHeart ph = this.getResultPurpleHeart();
        if(ph != null) ph.setStatusLastUpdateUser(user);
    }
    
    public String getPHDocumentType() {
        PurpleHeartDocument phDoc = this.getPHDocument();
        return (phDoc != null && phDoc.getDocumentType() != null) ? phDoc.getDocumentType().getCode() : null;
    }

    public String getPHDataSource() {
        PurpleHeartDocument phDoc = this.getPHDocument();
        return (phDoc != null && phDoc.getDataSource() != null) ? phDoc.getDataSource().getCode() : null;
    }

    public Date getPHDocumentReceivedDate() {
        PurpleHeartDocument phDoc = this.getPHDocument();
        return (phDoc != null) ? phDoc.getReceivedDate() : null;
    }
    
    public Boolean getPHDocumentAcceptable() {
        PurpleHeartDocument phDoc = this.getPHDocument();
        return (phDoc != null) ? phDoc.getAcceptable() : null;
    }

    public String getPHAssignedLAS() {
        return null;
    }

    public void addPHRegistry() {
        try {          
            this.getMergeRuleService().mergeRegistry(this.getPurpleHeart(),this.getResultPurpleHeart());
            
            // Set the defaults for the documents.
            this.setPHDocumentDefaults(this.getResultPurpleHeart());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge PH registry", e );
            throw new RuntimeException("Failed to merge PH registry", e );
        }
    }
    
    public void updatePHRegistry() {
        try {
            this.getMergeRuleService().mergeRegistry(this.getPurpleHeart(),this.getResultPurpleHeart());
            
            // Set the defaults for the documents.
            this.setPHDocumentDefaults(this.getResultPurpleHeart());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge PH registry", e );
            throw new RuntimeException("Failed to merge PH registry", e );
        }
    }
    
    /**
     * This method links unlinked PH registry to a new person if registry exists.
     */
    public void linkNewPersonPHRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        if(resultPerson != null) {
            //Get the registry record if exists and not linked to any veteran then ...
            PurpleHeart phRegistry =(PurpleHeart) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_PH_REGISTRY.getCode());
        
            //If the result veteran has no PH, there exists an unlinked registry then ...
            if(phRegistry != null && phRegistry.getPerson() == null) {
                resultPerson.setPurpleHeart(phRegistry);
            }
        }
    }
    
    /**
     * This method links unlinked PH registry to a existing person if registry exists.
     */
    public void linkExistingPersonPHRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        if(resultPerson != null) {
            PurpleHeart resultPH = resultPerson.getPurpleHeart();
            if(resultPH != null && resultPH.getRegistryTrait() == null) {
                //Get the registry record if exists and not linked to any veteran then ...
                PurpleHeart phRegistry =(PurpleHeart) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_PH_REGISTRY.getCode());
            
                //If there exists an unlinked registry then ...
                if(phRegistry != null && phRegistry.getPerson() == null) {
                    resultPerson.setPurpleHeart(phRegistry);
                }
            }
        }
    }
    
    /**
     * This method links unlinked PurpleHeart registry to the person if registry exists,
     * otherwise creates a new RegistryTrait and hook it to PurpleHeart.
     */
    public void linkPersonPHRegistry() throws RuleException 
    {
    	 Person resultPerson = this.getResultPerson();
    	 PurpleHeart resultPurpleHeart = (resultPerson != null) ? resultPerson.getPurpleHeart() : null;
    	 //PurpleHeart incomingPH=this.getPurpleHeart();
         //If the result shad is not already linked to the resgistry
         if(resultPurpleHeart != null && resultPurpleHeart.getRegistryTrait() == null) 
         {
        	 RegistryTrait registryTrait=null;
             //Get the registry record if exists
        	 PurpleHeart phRegistry =(PurpleHeart) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_PH_REGISTRY.getCode());
        	 if(phRegistry!=null )
        	 {
        		 //If registry record is associated to another person throw an exception.
        		 //even though the Registry_trait_id is attached to another person we still would like to associate it the result person because
        		 //the search was done using the SSN, First_Name and Last_Name. This is as per 9116        		 
        		 registryTrait =phRegistry.getRegistryTrait();
        		 if(phRegistry.getPerson()== null){
        			 phRegistry.setRegistryTrait(null);        			 
        		 }
        		 
        		 if( phRegistry.getDocuments()!=null)
        		 {        			 
        			 Set docs=new HashSet();
        			 try{
        				 docs=this.getMergeRuleService().mergeSets(phRegistry.getDocuments(), docs);
        			 }catch(ServiceException se)
        			 {
        				 throw new RuleException("Unable to merge PH documents",se);
        			 }
        			 if(!docs.isEmpty())
        				 resultPurpleHeart.addAllDocuments(docs);
        		 }
        	 }
            //If Registry trait is null, create new registry Trait
             registryTrait = (registryTrait == null) ? this.createRegistryTrait(resultPerson,RegistryType.CODE_PH_REGISTRY.getCode()) : registryTrait ;             
             resultPurpleHeart.setRegistryTrait(registryTrait);
             
             //delete orphan registry record.
             try{
                 if(phRegistry!=null && phRegistry.getPerson()== null)
                 	delete(phRegistry.getEntityKey());
                 }catch(ServiceException se)
                 {
                 	throw new RuleException("Unable to delete PurpleHeart Registry",se);
                 }
          }      	
    }
    
    /********************************* POW Getter/Setters **********************************************/

    public boolean getPOWIndicator() {
        PrisonerOfWar pow = this.getPrisonerOfWar();
        return (pow != null && pow.getPowIndicator() != null && pow.getPowIndicator().toBoolean() != null) ?  pow.getPowIndicator().toBoolean().booleanValue() : false;
    }
    
    public boolean getPristinePOWIndicator() {
        PrisonerOfWar pow = this.getPristinePrisonerOfWar();
        return (pow != null && pow.getPowIndicator() != null && pow.getPowIndicator().toBoolean() != null) ?  pow.getPowIndicator().toBoolean().booleanValue() : false;
    }
    
    public void setPOWIndicator(boolean indicator) {
        try {
            PrisonerOfWar pow = this.getResultPrisonerOfWar();
            if(pow != null) {
                String indCode = (indicator) ? Indicator.YES.getCode() : Indicator.NO.getCode();
                pow.setPowIndicator((Indicator)this.getLookupService().getByCode(Indicator.class,indCode));
            }
        } catch(ServiceException e) {
            this.logger.debug( "Failed to find Indicator lookup", e);
            throw new RuntimeException("Failed to find Indicator lookup", e);
        }
    }
    
    public void setPOWDateEntered(Date date) {
        PrisonerOfWar pow = this.getResultPrisonerOfWar();
        if(pow != null) pow.setDateEntered(date);
    }
    
    public void setPOWEnteredBy(String user) {
        PrisonerOfWar pow = this.getResultPrisonerOfWar();
        if(pow != null) pow.setUser(user);
    }

    public String getPOWDocumentType() {
        POWEpisode powEpi = this.getPOWEpisode();
        return (powEpi != null && powEpi.getDocumentType() != null) ? powEpi.getDocumentType().getCode() : null;
    }

    public String getPOWDataSource() {
        POWEpisode powEpi = this.getPOWEpisode();
        return (powEpi != null && powEpi.getDataSource() != null) ? powEpi.getDataSource().getCode() : null;
    }
    
    public Date getPOWCaptureDate() {
        POWEpisode powEpi = this.getPOWEpisode();
        return (powEpi != null && powEpi.getCaptureDate() != null) ? ImpreciseDateUtils.getDateWithDefault(powEpi.getCaptureDate()) : null;
    }
    
    public Date getPOWReleaseDate() {
        POWEpisode powEpi = this.getPOWEpisode();
        return (powEpi != null && powEpi.getReleaseDate() != null) ? ImpreciseDateUtils.getDateWithDefault(powEpi.getReleaseDate()) : null;
    }

    public String getPOWConfinementLocation() {
        POWEpisode powEpi = this.getPOWEpisode();
        return (powEpi != null && powEpi.getConfinementLocation() != null) ? powEpi.getConfinementLocation().getCode() : null;
    }



    public void addPOWRegistry() {
        try {
            this.getMergeRuleService().mergeRegistry(this.getPrisonerOfWar(),this.getResultPrisonerOfWar());
            
            // Set the defaults for the episodes.
            this.setPOWEpisodeDefaults(this.getResultPrisonerOfWar());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge POW registry", e );
            throw new RuntimeException("Failed to merge POW registry", e );
        }
    }
    
    public void updatePOWRegistry() {
        try {
            this.getMergeRuleService().mergeRegistry(this.getPrisonerOfWar(),this.getResultPrisonerOfWar());
            
            // Set the defaults for the episodes.
            this.setPOWEpisodeDefaults(this.getResultPrisonerOfWar());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge POW registry", e );
            throw new RuntimeException("Failed to merge POW registry", e );
        }
    }

    /**
     * This method links unlinked POW registry to a new person if registry exists.
     */
    public void linkNewPersonPOWRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        
        //If the result person is null, do nothing and return
        if(resultPerson != null) {
            //Get the registry record if exists and not linked to any veteran then ...
            PrisonerOfWar powRegistry =(PrisonerOfWar) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_POW_REGISTRY.getCode());
            
            //If the result veteran has no POW, there exists an unlinked registry then ...
            if(powRegistry != null && powRegistry.getPerson() == null) {
                resultPerson.setPrisonerOfWar(powRegistry);
            }
        }
    }
    
    /**
     * This method links unlinked POW registry to a existing person if registry exists.
     */
    public void linkExistingPersonPOWRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        if(resultPerson != null) {
            PrisonerOfWar resultPOW = resultPerson.getPrisonerOfWar();
            if(resultPOW != null && resultPOW.getRegistryTrait() == null) {
                //Get the registry record if exists and not linked to any veteran then ...
                PrisonerOfWar powRegistry =(PrisonerOfWar) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_POW_REGISTRY.getCode());
                
                //If there exists an unlinked registry then ...
                if(powRegistry != null && powRegistry.getPerson() == null) {
                    resultPerson.setPrisonerOfWar(powRegistry);
                }
            }
        }
    }
    
    /**
     * This method links unlinked POW registry to the person if registry exists,
     * otherwise creates a new RegistryTrait and hook it to POWRegistry.
     */
    public void linkPersonPOWRegistry() throws RuleException 
    {
    	 Person resultPerson = this.getResultPerson();
    	 PrisonerOfWar resultPrisonerOfWar = (resultPerson != null) ? resultPerson.getPrisonerOfWar() : null;
    	 PrisonerOfWar incomingPOW = this.getPrisonerOfWar();

         //If the result pow is not already linked to the resgistry
         if(resultPrisonerOfWar != null && resultPrisonerOfWar.getRegistryTrait() == null) {
         	RegistryTrait registryTrait = null;
            
         	//Get the registry record if exists
            PrisonerOfWar powRegistry =(PrisonerOfWar) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_POW_REGISTRY.getCode());
            if(powRegistry != null) {
                //removed If registry record is associated to another person throw an exception.
            	//even though the Registry_trait_id is attached to another person we still would like to associate it the result person because
       		 	//the search was done using the SSN, First_Name and Last_Name. This is as per 9116         		
        		registryTrait = powRegistry.getRegistryTrait();
        		if(powRegistry.getPerson()== null){
        			powRegistry.setRegistryTrait(null);        			
        		}                
        	 
	        	if(powRegistry.getEpisodes()!=null)
	        	{
	        	    Set episodes=new HashSet();
	        	    try{
	    				 episodes=this.getMergeRuleService().mergeSets(powRegistry.getEpisodes(), episodes);
	    			}catch(ServiceException se) {
	    				 throw new RuleException("Unable to merge POW episodes",se);
	    			}	    			 
	        		Set incomingEpisodes=(incomingPOW.getEpisodes()!=null)?incomingPOW.getEpisodes():new HashSet();
	        		removeMatchedPOWEpisodes(episodes,incomingEpisodes);
	        		if(!episodes.isEmpty())
	        		    resultPrisonerOfWar.addAllEpisodes(episodes);
	        	} 	        	 
        	 }
        	 //If Registry trait is null, create new registry Trait
             registryTrait = (registryTrait == null) ? this.createRegistryTrait(resultPerson,RegistryType.CODE_POW_REGISTRY.getCode()) : registryTrait ;             
             resultPrisonerOfWar.setRegistryTrait(registryTrait);
             //delete orphan registry record.
             try{
                 if(powRegistry!=null && powRegistry.getPerson()== null)
                 	delete(powRegistry.getEntityKey());
                 }catch(ServiceException se)
                 {
                 	throw new RuleException("Unable to delete POW Registry",se);
                 }
          }
    }
    
    /* (non-Javadoc)
     * @see gov.va.med.esr.common.rule.parameter.BaseParameter#isUpdateFromGUI()
     */
    public boolean isUpdateFromGUI() {
        RegistryInputData registryInputData = getRegistryInputData();
        return registryInputData.isDataFromGUI();
    }
    
    /**
     * This method removes POWEpisodes from episodes1 if matching POWEpisodes exists in episodes2.
     * @param episodes1
     * @param episodes2
     * @return
     */
    private Set removeMatchedPOWEpisodes(Set episodes1, Set episodes2)
    {
    	if(episodes1!=null && !episodes1.isEmpty()&& episodes2!=null && !episodes2.isEmpty())
    	{
    		for(Iterator it=episodes1.iterator();it.hasNext();)
    		{
    			POWEpisode episode=(POWEpisode)it.next();
    			POWEpisode matchingEpisode=getMatchingPOWEpisode(episode,episodes2);
    			if(matchingEpisode!=null)
    				it.remove();
    		}
    	}
    	return episodes1;
    }
    
    /**
     * This method returns matching POWEpisode if one exists in passed Collection.
     * @param pOWEpisode
     * @param episodes
     * @return
     */
    private POWEpisode getMatchingPOWEpisode(POWEpisode pOWEpisode, Set episodes)
    {
	    if(pOWEpisode!=null && episodes!=null)
	    {
	    	for(Iterator it=episodes.iterator();it.hasNext();)
	    	{
	    		POWEpisode episode=(POWEpisode)it.next();
	    		if(match(pOWEpisode,episode))
	    			return episode;
	    	}	    	
	    }
	    return null;
    }
    
    /**
     * This method returns true if they are equal.
     * @param source
     * @param target
     * @return
     */
    private boolean match(POWEpisode source, POWEpisode target) {
        // Use business properties to determine if the 2 entities are the same
        final EqualsBuilder builder = new EqualsBuilder();
        builder.append( source.getClass(), target.getClass() )               
               .append( source.getCaptureDate(), target.getCaptureDate() )
               .append( source.getReleaseDate(), target.getReleaseDate() )              
               .append( source.getCampLocation(), target.getCampLocation());  
        
        return builder.isEquals();     
    } 
    
    /**)
     * @see gov.va.med.esr.common.rule.RegistryInput#isExactMatch()
     */
    public boolean isExactMatch() {
        return this.getRegistryInputData() != null ? this.getRegistryInputData().isExactMatch() : false;
    }

    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#isPersonIdMatched()
     */
    public boolean isPersonIdMatched()
    {
        return this.getRegistryInputData() != null ? this.getRegistryInputData().isExactMatchDifferentEpisode() : false;
    }

    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#isAmbiguousMatch()
     */
    public boolean isAmbiguousMatch()
    {
        return this.getRegistryInputData() != null ? this.getRegistryInputData().isAmbiguousMatch() : false;
    }

    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#isSameEpisode()
     */
    public boolean isSameEpisode()
    {
        return this.getRegistryInputData() != null ? this.getRegistryInputData().isExactMatchSameEpisode() : false;
    }

    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#setPersonId()
     */
    public void setPersonId()
    {
        // not necessary
    }    

    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#addRegistry()
     */
    public void addRegistry() {
        updateRegistry();
    }
    
    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#updateRegistry()
     */
    public void updateRegistry() {
        try {
            String type = this.getRegistryType();
            if (RegistryType.CODE_PH_REGISTRY.getCode().equals(type)) {
                this.getMergeRuleService().mergeRegistry((PurpleHeart)this.getIncomingRegistry(), (PurpleHeart)this.getResultRegistry(), false);                
            }
            else
            if (RegistryType.CODE_POW_REGISTRY.getCode().equals(type)) {
                this.getMergeRuleService().mergeRegistry((PrisonerOfWar)this.getIncomingRegistry(), (PrisonerOfWar)this.getResultRegistry(), false);                
            }
            else
            if (RegistryType.CODE_SHAD_REGISTRY.getCode().equals(type)) {
                this.getMergeRuleService().mergeRegistry((SHAD)this.getIncomingRegistry(), (SHAD)this.getResultRegistry(), false);                
            }            
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge registry", e );
            throw new RuntimeException("Failed to merge registry", e );
        }
        LoadRegistryResult lrr = this.getRegistryInputData() != null ? this.getRegistryInputData().getLoadRegistryResult() : null;
        if (lrr != null) {
            if (!lrr.isAmbiguousMatch() && !lrr.isExactMatchSameEpisode()) {
                lrr.setNewRegistry(true);                
            }
        }
    }
    
    
    
    /**
     * @see gov.va.med.esr.common.rule.RegistryInput#writeRegistryException(java.lang.String)
     */
    public void writeRegistryException(String exceptionType) {
        RegistryInputData rid = this.getRegistryInputData();
        if (exceptionType != null && rid != null) {
            LoadRegistryResult loadRegistryResult = this.getRegistryInputData().getLoadRegistryResult();
            if (loadRegistryResult != null) {
                try
                {
                    loadRegistryResult.setExceptionType((ReportExceptionType)getLookupService().getByCode(ReportExceptionType.class,exceptionType));
                } catch (ServiceException e)
                {
                    this.logger.error( "Failed to find Indicator lookup", e);
                    throw new RuntimeException("Failed to find Indicator lookup", e);
                }
            }
        }
    }    
    
    /******************************** SHAD Getter/Setters **********************************************/
    
    public boolean getSHADIndicator() {
        SHAD shad = this.getSHAD();
        return (shad != null && shad.getShadIndicator() != null && shad.getShadIndicator().toBoolean() != null) ?  shad.getShadIndicator().toBoolean().booleanValue() : false;
    }
    
    public boolean getPristineSHADIndicator() {
        SHAD shad = this.getPristineSHAD();
        return (shad != null && shad.getShadIndicator() != null && shad.getShadIndicator().toBoolean() != null) ?  shad.getShadIndicator().toBoolean().booleanValue() : false;
    }
    
    public void setSHADIndicator(boolean indicator) {
        try {
            SHAD shad = this.getResultSHAD();
            if(shad != null) {
                String indCode = (indicator) ? Indicator.YES.getCode() : Indicator.NO.getCode();
                shad.setShadIndicator((Indicator)this.getLookupService().getByCode(Indicator.class,indCode));
            }
        } catch(ServiceException e) {
            this.logger.debug( "Failed to find Indicator lookup", e);
            throw new RuntimeException("Failed to find Indicator lookup", e);
        }
    }
    
    public String getSHADDocumentType() {
        SHADDocument shadDoc = this.getSHADDocument();
        return (shadDoc != null && shadDoc.getDocumentType() != null) ? shadDoc.getDocumentType().getCode() : null;
    }
    
    public Date getSHADDocumentReceivedDate() {
        SHADDocument shadDoc = this.getSHADDocument();
        return (shadDoc != null) ? shadDoc.getReceivedDate() : null;
    }
    
    public void addSHADRegistry() {
        try {
            this.getMergeRuleService().mergeRegistry(this.getSHAD(),this.getResultSHAD());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge SHAD registry", e );
            throw new RuntimeException("Failed to merge SHAD registry", e );
        }
    }
    
    public void updateSHADRegistry() {
        try {
            this.getMergeRuleService().mergeRegistry(this.getSHAD(),this.getResultSHAD());
        } catch( ServiceException e ) {
            this.logger.debug( "Failed to merge SHAD registry", e );
            throw new RuntimeException("Failed to merge SHAD registry", e );
        }
    } 
	
    /**
     * This method links unlinked SHAD registry to a new person if registry exists.
     */
    public void linkNewPersonSHADRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        if(resultPerson != null) {
            //Get the registry record if exists and not linked to any veteran then ...
            SHAD shadRegistry =(SHAD) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_SHAD_REGISTRY.getCode());
            
            //If the result veteran has no SHAD, there exists an unlinked registry then ...
            if(shadRegistry != null && shadRegistry.getPerson() == null) {
                resultPerson.setShad(shadRegistry);
            }
        }
    }
        
    /**
     * This method links unlinked SHAD registry to a existing person if registry exists.
     */
    public void linkExistingPersonSHADRegistry() throws RuleException {
        Person resultPerson = this.getResultPerson();
        if(resultPerson != null) {
            SHAD resultSHAD = resultPerson.getShad();
            if(resultSHAD != null && resultSHAD.getRegistryTrait() == null) {
                //Get the registry record if exists and not linked to any veteran then ...
                SHAD shadRegistry =(SHAD) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_SHAD_REGISTRY.getCode());
                
                //If there exists an unlinked registry then ...
                if(shadRegistry != null && shadRegistry.getPerson() == null) {
                    resultPerson.setShad(shadRegistry);
                }
            }
        }
    }
    
   /**
    * This method links unlinked SHAD registry to the person if registry exists,
    * otherwise creates a new RegistryTrait and hook it to SHAD.
    */
    public void linkPersonSHADRegistry() throws RuleException {
        
        Person resultPerson = this.getResultPerson();
        SHAD resultShad = (resultPerson != null) ? resultPerson.getShad() : null;  
       // SHAD incomingShad=this.getSHAD();
        //If the result shad is not already linked to the resgistry
        if(resultShad != null && resultShad.getRegistryTrait() == null) 
        {
        	RegistryTrait registryTrait=null;
            //Get the registry record if exists
            SHAD shadRegistry =(SHAD) this.getUnlinkedRegistry(resultPerson,RegistryType.CODE_SHAD_REGISTRY.getCode());       	
        	if(shadRegistry!=null )
        	{    
        		//Even though the Registry_trait_id is attached to another person we still would like to associate it the result person because
       		 	//the search was done using the SSN, First_Name and Last_Name. This is as per 9116        		
        		registryTrait=shadRegistry.getRegistryTrait();
        		if(shadRegistry.getPerson()== null){
        			shadRegistry.setRegistryTrait(null);        			
        		}        		
        		resultShad.setClaimNumber(shadRegistry.getClaimNumber());
        		if(shadRegistry.getDocuments()!=null)
        		{  		
	        		Set docs=new HashSet();
       			 	try{
       			 		docs=this.getMergeRuleService().mergeSets(shadRegistry.getDocuments(), docs);
	       			 }catch(ServiceException se)
	       			 {
	       				 throw new RuleException("Unable to merge SHAD documents",se);
	       			 }
	       			 if(!docs.isEmpty())
	       				 resultShad.addAllDocuments(docs);	       	  
        		}
        	}            
            registryTrait = (registryTrait == null) ? this.createRegistryTrait(resultPerson,RegistryType.CODE_SHAD_REGISTRY.getCode()) : registryTrait ;              
            resultShad.setRegistryTrait(registryTrait);
            //delete orphan registry record.
            try{
            if(shadRegistry!=null && shadRegistry.getPerson()== null)
            	delete(shadRegistry.getEntityKey());
            }catch(ServiceException se)
            {
            	throw new RuleException("Unable to delete SHAD Registry",se);
            }
         }
     }
    
    /**
     * This method creates  a RegistryTrait from Person object.
     * @param person
     * @param registryType
     * @return
     */
     public RegistryTrait createRegistryTrait(Person person,String registryType)
     throws RuleException{
         RegistryTrait registryTrait = new RegistryTrait();
         
         try {
             registryTrait.setRegistryType((RegistryType)this.getLookupService().getByCode(RegistryType.class,registryType));
         } catch(Exception ex) {
             throw new RuleException("Unable to look up registry type",ex);
         }
         
         SSN ssn = person.getOfficialSsn();
         registryTrait.setSsn(ssn != null ? ssn.getFormattedSsnText() : null);
         Name name = person.getLegalName();
         if(name != null) {
             registryTrait.setLastName(name.getFamilyName());
             registryTrait.setFirstName(name.getGivenName());
             registryTrait.setMiddleName(name.getMiddleName());
             registryTrait.setPrefix(name.getPrefix());
             registryTrait.setSuffix(name.getSuffix());
         }
         DeathRecord deathRecord=person.getDeathRecord();         
         registryTrait.setDeathDate(deathRecord!=null?deathRecord.getDeathDate():null);                 
         Set msns = person.getMilitaryServiceNumbers();
         for(Iterator iter=msns.iterator(); iter.hasNext();) {
             RegistryTraitDetail traitDetail = new RegistryTraitDetail();
             traitDetail.setMilitaryServiceNumber((String)iter.next());
             registryTrait.addRegistryTraitDetail(traitDetail);
         }
         return registryTrait;
     }
    
    public Person getIncomingPerson() {
        return (this.getRegistryInputData() != null) ? this.getRegistryInputData().getIncomingPerson() : null;
    }
    
    public Person getResultPerson() {
        return (this.getRegistryInputData() != null) ? this.getRegistryInputData().getResultPerson() : null;
    }

    private void setPHDocumentDefaults(PurpleHeart ph) {
        // Set the defaults for the documents.
        if(ph != null && ph.getDocuments() != null) {
            for(Iterator iter=ph.getDocuments().iterator(); iter.hasNext();) {
                PurpleHeartDocument doc = (PurpleHeartDocument)iter.next();
                if(doc != null && doc.getEntityKey() == null) {
                    doc.setLoginDate(this.getCurrentDate());
                    doc.setLoggedInUser(this.getLoggedInUser());
                }
            }
        }
    }
    
    private void setPOWEpisodeDefaults(PrisonerOfWar pow) {
        // Set the defaults for the episodes.
        if(pow != null && pow.getEpisodes() != null) {
            for(Iterator iter=pow.getEpisodes().iterator(); iter.hasNext();) {
                POWEpisode episode = (POWEpisode)iter.next();
                if(episode != null && episode.getEntityKey() == null) {
                    episode.setDateEntered(this.getCurrentDate());
                }
            }
        }
    }
    /**
     * This method deletes registry record from database.
     * @param entityKey
     * @throws ServiceException
     */
    private void delete(EntityKey entityKey) throws ServiceException {
        Validate.notNull(entityKey.getKeyValue(),"Entity Key Value can not be NULL");
        Validate.notNull(entityKey.getEntityClass(),"Entity Class can not be NULL");        
        try{
            getRegistryDAO().removeObject(entityKey);
        }catch(DAOException ex) {
            throw new ServiceException("Error while retrieving entity of type: " + entityKey.getEntityClass().getName(), ex);                                
        }
    }
    
    public PurpleHeart getPurpleHeart() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_PH_REGISTRY.getName())) ? (PurpleHeart)this.getRegistry() : null;
    }
    
    private PurpleHeart getResultPurpleHeart() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_PH_REGISTRY.getName())) ? (PurpleHeart)this.getResultRegistry() : null;
    }
    
    private PurpleHeart getPristinePurpleHeart() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_PH_REGISTRY.getName())) ? (PurpleHeart)this.getPristineRegistry() : null;
    }
    
    public PrisonerOfWar getPrisonerOfWar() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_POW_REGISTRY.getName())) ? (PrisonerOfWar)this.getRegistry() : null;
    }
    
    private PrisonerOfWar getResultPrisonerOfWar() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_POW_REGISTRY.getName())) ? (PrisonerOfWar)this.getResultRegistry() : null;
    }
    
    private PrisonerOfWar getPristinePrisonerOfWar() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_POW_REGISTRY.getName())) ? (PrisonerOfWar)this.getPristineRegistry() : null;
    }
    
    public SHAD getSHAD() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_SHAD_REGISTRY.getName())) ? (SHAD)this.getRegistry() : null;
    }
    
    private SHAD getResultSHAD() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_SHAD_REGISTRY.getName())) ? (SHAD)this.getResultRegistry() : null;
    }
    
    private SHAD getPristineSHAD() {
        return (StringUtils.equals(this.getRegistryType(),RegistryType.CODE_SHAD_REGISTRY.getName())) ? (SHAD)this.getPristineRegistry() : null;
    }
    
    public RegistryTrait getRegistryTrait(Registry registry) {
        return (registry != null) ? registry.getRegistryTrait() : null;
    }
    
    private RegistryTrait getRegistryTrait() {
        Registry registry = this.getRegistry();
        return (registry != null) ? registry.getRegistryTrait() : null;
    }
    
    public Registry getRegistry() {
        return (this.getIncomingData() instanceof Registry) ? (Registry)this.getIncomingData() : null;
    }
    
    private Registry getResultRegistry() {
        return (this.getResultData() instanceof Registry) ? (Registry)this.getResultData() : null;
    }
    
    private Registry getIncomingRegistry() {
        return (this.getIncomingData() instanceof Registry) ? (Registry)this.getIncomingData() : null;
    }    
    
    private Registry getPristineRegistry() {
        return (this.getPristineData() instanceof Registry) ? (Registry)this.getPristineData() : null;
    }
    
    private PurpleHeartDocument getPHDocument() {
        return (this.getDocument() instanceof PurpleHeartDocument) ? (PurpleHeartDocument)this.getDocument() : null;
    }
    
    private POWEpisode getPOWEpisode() {
        return (this.getDocument() instanceof POWEpisode) ? (POWEpisode)this.getDocument() : null;
    }
    
    private SHADDocument getSHADDocument() {
        return (this.getDocument() instanceof SHADDocument) ? (SHADDocument)this.getDocument() : null;
    }
    
    private Document getDocument() {
        RuleDataAware ruleDataAware = this.getRuleDataAware();
        return (ruleDataAware instanceof RegistryInputData) ? ((RegistryInputData)ruleDataAware).getDocument() : null;
    }

    private String registryDaoName = null;
    public void setRegistryDaoName(String registryDaoName) {
        this.registryDaoName = registryDaoName;
    }

    private RegistryDAO getRegistryDAO() throws ServiceException {
        return (RegistryDAO) this.getComponent(this.registryDaoName);            
    }
    
    private Registry getUnlinkedRegistry(Person person, String registryType) throws RuleException{
        try {
            RegistryType regType = getRegistryTypeFromCode(registryType);
            if(person != null && regType != null) {
                return this.getRegistryDAO().getRegistry(person, regType);
            }
        } catch(Exception ex) {
            throw new RuleException("Error while getting the registry trait",ex);
        }
        return null;
    }
    
    private RegistryInputData getRegistryInputData() {
        RuleDataAware ruleDataAware = this.getRuleDataAware();
        if (ruleDataAware instanceof RegistryInputData) {
            return (RegistryInputData) ruleDataAware;
        }
        return null;
    }
    
    private RegistryType getRegistryTypeFromCode(String rType) throws RuleException {
        try {
            return (RegistryType)this.getLookupService().getByCode(RegistryType.class,rType);
        } catch(Exception ex) {
            throw new RuleException("Error while getting the RegistryType lookup for code = " + rType);
        }
        
        
    }
}