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

// Framework classes
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;


import gov.va.med.fw.rule.RuleDataAware;
import gov.va.med.fw.rule.RuleException;
import gov.va.med.fw.service.ServiceException;

// ESR Classes
import gov.va.med.esr.common.clock.Clock;
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.lookup.DecorationStatus;
import gov.va.med.esr.common.model.lookup.PHDataSource;
import gov.va.med.esr.common.model.lookup.PHDocumentType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.rule.PurpleHeartInput;
import gov.va.med.esr.common.rule.data.PHInputData;
import gov.va.med.esr.common.model.lookup.RejectionRemark;

/**
 * This class is a facade that provides access to purple heart data. Parameter
 * objects are loaded into ILOG working memory for use by rules.
 * 
 * @author Muddaiah Ranga
 * @version 1.0
 */
/**
 * @author DNS   KATIKM
 *
 */
public class PurpleHeartInputParameter extends BaseParameter implements	PurpleHeartInput {

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 4295682708902703724L;
    
    private Person priorPersonForPurpleHeart = null;
    
    private PurpleHeartDocument resultPurpleHeartDocument = null;    
    
    private Date dateOfBirth = null;
    
	/**
	 * A default constructor
	 */
	public PurpleHeartInputParameter() {
		super();
	}

	/**
	 * Gets the purple heart indicator for the incoming person.
	 */
	public String getPurpleHeartIndicator() throws RuleException {
		return this.getPurpleHeartIndicator(this.getIncomingPerson());
	}

	/**
	 * Gets the purple heart status for the incoming person.
	 */
	public String getPurpleHeartStatus() throws RuleException {
		return this.getPurpleHeartStatus(this.getIncomingPerson());
	}

	/**
	 * Gets the purple heart indicator for the pristine person.
	 */
	public String getVeteranPurpleHeartIndicator() {
		return this.getPurpleHeartIndicator(this.getPristinePerson());
	}


	/**
	 * Sets the purple heart indicator for the result person.
	 */
	public void setPurpleHeart( String indicator ) {
        // Apply change to incoming, update the onfile later
		if( indicator != null ) {
			this.setPurpleHeartIndicator( YES_INDICATOR.equals( indicator ) ? Boolean.TRUE : Boolean.FALSE );
		}
	}

	public void setPurpleHeartIndicator( Boolean indicator ) {

		if( indicator != null ) {
            // Apply change to incoming, update the onfile later
			// Set a rejection remark to null if an indicator is Boolean.TRUE
			PurpleHeart incoming = this.getIncomingPurpleHeart();
            if (incoming != null) {
                RejectionRemark remark = incoming.getRejectionRemark();
                incoming.setRejectionRemark(Boolean.TRUE.equals( indicator ) ? null : remark);
                incoming.setPhIndicator( indicator );                
            }
		}
	}

	/**
	 * Sets the purple heart status for the result person.
	 */
	public void setPurpleHeartStatus( String status ) throws RuleException {
		try {
            // Apply change to incoming, update the onfile later            
			PurpleHeart result = this.getIncomingPurpleHeart();
			if( result != null ) {
				result.setStatus( getLookupService().getDecorationStatusByCode( status ) );
			}
		}
		catch (ServiceException e) {
			throw new RuleException("Failed to set Purple Heart Status", e);
		}
	}

	/**
	 * Sets the purple heart rejection remarks for the result person.
	 */
	public void setRejectedRemarks( String remark ) throws RuleException {
		try {
            // Apply change to incoming, update the onfile later 
			PurpleHeart result = this.getIncomingPurpleHeart(); //12484 revert back to inocming data
			if( result != null ) {
				result.setRejectionRemark( remark == null ? null : 
					getLookupService().getRejectionRemarkByCode( remark ) );
			}
		}
		catch (ServiceException e) {
			throw new RuleException("Failed to set Rejected Remarks", e);
		}
	}


	/**
	 * Gets the purple heart received facility.
	 */
	public VAFacility getReceivedFacility() {
		PurpleHeart purpleHeart = this.getIncomingPurpleHeart();
		return purpleHeart != null ? purpleHeart.getFacility() : null;
	}

	/**
	 * Sets the purple heart received facility.
	 */
	public void setReceivedFacility(VAFacility facility) {
		PurpleHeart result = this.getIncomingPurpleHeart();
		if( result != null ) {
			result.setFacility( facility );
		}
	}

	/**
	 * Updates the result person purple heart with the data from the incoming
	 * person's purple heart.
	 */
	public void updatePurpleHeart() throws RuleException {
		
		PurpleHeart incoming = getIncomingPurpleHeart();
		if (incoming != null) {
			try {
				PurpleHeart result = this.getResultPurpleHeart();
				if( result == null ) {
					result = new PurpleHeart();
					this.getResultPerson().addDecoration( result );
				}
				this.getMergeRuleService().mergePurpleHeart( incoming, result );
			}
			catch (ServiceException e) {
				throw new RuleException("Failed to update Purple Heart", e);
			}
		}
		else {
			// Delete all decorations
			this.getResultPerson().removeAllDecorations();
		}
	}
	
	/**
	 * This method purpleHeart Registry.
	 * @throws ServiceException
	 */
	 public void updatePurpleHeartRegistry() throws ServiceException 
	    {
//	        Person incoming = this.getIncomingPerson();
//	        PurpleHeart purpleHeart = (incoming != null) ? incoming.getPurpleHeart() : null;
//	        Person onFile = this.getResultPerson();
//	        if(purpleHeart != null) 
//	        {            
//	        	PurpleHeart onFilePurpleHeart = (onFile != null) ? onFile.getPurpleHeart() : null;
//	            if(onFilePurpleHeart == null) 
//	            {
//	            	onFilePurpleHeart = new PurpleHeart();                              
//	            }            
//	            if(onFilePurpleHeart.getRegistryTrait() == null) 
//	            {
//	            	onFilePurpleHeart.setRegistryTrait(new RegistryTrait());
//	            }     
//	            
//	            this.getMergeRuleService().mergeRegistry(purpleHeart,onFilePurpleHeart);
//	            onFile.setPurpleHeart(onFilePurpleHeart);
//	        } 
//	        else 
//	        {
//	            onFile.setPurpleHeart(null);
//	        }
	    }

	/**
	 * Gets the purple heart of the pristine person.
	 */
	public PurpleHeart getVeteranPurpleHeart() {
		Person pristine = this.getPristinePerson();
		return pristine.getPurpleHeart();
	}

	public boolean isUpdateFromHEC() {
		return super.isUpdateFromGUI();
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPurpleHeart() Gets
	 *      Purple Heart of Incoming Person
	 */
	public PurpleHeart getPurpleHeart() {
		return this.getHelperService().getPurpleHeart(this.getIncomingPerson());
	}
    
    // Start of PH methods for Triggering letters
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPHDocumentAcceptable()
     */
    public Boolean getPHDocumentAcceptable() {
    	return isPHDocumentAcceptable(this.getIncomingPerson());
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPHRejectedRemarks()
     */
    public String getPHRejectedRemarks() {
        PurpleHeart ph = this.getIncomingPurpleHeart();
        return (ph != null && ph.getRejectionRemark() != null) ?
                ph.getRejectionRemark().getCode() : null;
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getVeteranPHRejectedRemarks()
     */
    public String getVeteranPHRejectedRemarks() {
        PurpleHeart ph = this.getVeteranPurpleHeart();
        return (ph != null && ph.getRejectionRemark() != null) ?
                ph.getRejectionRemark().getCode() : null;
    }

    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPriorPHDocumentAcceptable()
     */
    public Boolean getPriorPHDocumentAcceptable() throws RuleException  {
        if ( priorPersonForPurpleHeart == null ) {
            this.priorPersonForPurpleHeart = this.getPriorPersonForPurpleHeart();
        }
        return isPHDocumentAcceptable(this.priorPersonForPurpleHeart);
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPriorPurpleHeartStatus()
     */
    public String getPriorPurpleHeartStatus() throws RuleException {
        if ( priorPersonForPurpleHeart == null ) {
            this.priorPersonForPurpleHeart = this.getPriorPersonForPurpleHeart();
        }
        
        return this.priorPersonForPurpleHeart != null ?
                this.getPurpleHeartStatus(this.priorPersonForPurpleHeart) : null;            
    }
 
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#is37DayClockExpired()
     */
    public boolean is37DayClockExpired() {
        Clock.Type fired = this.getFiredClockType();
        return fired != null ? Clock.Type.PH_37_DAY_CLOCK.getName().equals(fired.getName()) : false;
    }

    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#start37DayLetterClock()
     */
    public void start37DayLetterClock() throws RuleException {
        try {
            this.getScheduledTaskService().startPHLetterClock(this.getIncomingPerson());
        } catch (ServiceException e) {
            throw new RuleException("Failed to start 37 day clock", e);
        }
    }
    
    // End of letter related methods
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#acceptPHFromUI()
     */
    public void acceptPHFromUI() throws RuleException {
        this.updatePurpleHeart();
    }
    
    /**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#acceptPHFromMSDS()
	 */
	public void acceptPHFromMSDS() throws RuleException {
		PurpleHeart incoming = getIncomingPurpleHeart();
		if (incoming != null) {
			try {
				PurpleHeart result = this.getResultPurpleHeart();
				if( result == null ) {
					result = new PurpleHeart();
					this.getResultPerson().addDecoration( result );
				}
				this.getMergeRuleService().mergePurpleHeart( incoming, result );
			}
			catch (ServiceException e) {
				throw new RuleException("Failed to update Purple Heart", e);
			}
		}
		// Only add/update data in MSDS processing, don't delete 
	}
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#cancelPHLetterClock()
     */
    public void cancelPHLetterClock() throws RuleException {
        try {
            this.getScheduledTaskService().cancelClock(this.getIncomingPerson(), Clock.Type.PH_37_DAY_CLOCK, Clock.Group.PH_CLOCK_GROUP);            
        }
        catch (ServiceException e) {
            throw new RuleException("Failed to cancel PH letter clock", e);
        }        
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#cancelPHPendingClock()
     */
    public void cancelPHPendingClock() throws RuleException {
        try {
            this.getScheduledTaskService().cancelClock(this.getIncomingPerson(), Clock.Type.PH_14_DAY_CLOCK, Clock.Group.PH_CLOCK_GROUP);            
        }
        catch (ServiceException e) {
            throw new RuleException("Failed to cancel PH pending clock", e);
        }       
    }

    /**
     * Sets the purple heart pending clock.
     */
    public void updatePHPendingClock() throws RuleException {
        try {
            this.getScheduledTaskService().startPHPendingClock(this.getIncomingPerson());
        } catch (ServiceException e) {
            throw new RuleException("Failed to start PH pending clock", e);
        }
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getVeteranReceivedDate()
     */
    public Date getVeteranReceivedDate() {
        PurpleHeartDocument phd = this.getAcceptablePHDocument(this.getPristinePerson());
        return phd != null ? phd.getReceivedDate() : null;
    }
    
    public Date getVeteranDateOfBirth() {
        if ( dateOfBirth == null ) {
            this.dateOfBirth = this.getDateOfBirth(this.getIncomingPerson());
        }
        return this.dateOfBirth;
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#hasPHPendingClockExpired()
     */
    public boolean hasPHPendingClockExpired() {
        Clock.Type fired = this.getFiredClockType();
        return fired != null ? Clock.Type.PH_14_DAY_CLOCK.getName().equals(fired.getName()) : false;
    }
    
    /**
     * Initial document already exists or received
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#isFirstDocumentReceived()
     */
    public boolean isFirstDocumentReceived() {
        PurpleHeart incoming = this.getIncomingPurpleHeart();
        PurpleHeart current = this.getVeteranPurpleHeart();
        if ((current != null && current.getDocuments().size() > 0) ||
            (incoming != null && incoming.getDocuments().size() > 0))
        {
        	return true;
        }
      return false;
    }
    
    public boolean isAdditionalDocumentReceived() {
        PurpleHeart incoming = this.getIncomingPurpleHeart();
        PurpleHeart current = this.getVeteranPurpleHeart();
        if (incoming != null && current != null) {
            return (current.getDocuments().size() > 0 &&                
                incoming.getDocuments().size() > current.getDocuments().size());
        }
        return false;
    }
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#setLoginDate(java.util.Date)
     */
    public void setLoginDate(Date loginDate) {
        PurpleHeartDocument result = this.getLatestPurpleHeartDocument();
        if (result != null) {
            result.setLoginDate(loginDate);
        }
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#setStatusUpdateDate(java.util.Date)
     */
    public void setStatusUpdateDate(Date statusUpdateDate) {
        PurpleHeart result = this.getIncomingPurpleHeart();
        if (result != null) {
            result.setStatusLastEditDate(statusUpdateDate);
        }
    }
    
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getDocumentType()
     */
    public String getDocumentType() {
        PurpleHeartDocument  phd = this.getIncomingPurpleHeartDocument();
        return (phd != null && phd.getDocumentType() != null)  ?
                phd.getDocumentType().getCode() : null;
    }
    
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getReceivedDate()
     */
    public Date getReceivedDate() {
        PurpleHeartDocument  phd = this.getIncomingPurpleHeartDocument();
        return phd != null ? phd.getReceivedDate() : null;
    }
    /**
     * @see gov.va.med.esr.common.rule.PurpleHeartInput#getDocumentAcceptable()
     */
    public Boolean getDocumentAcceptable()
    {
    	PurpleHeartDocument  phd = this.getIncomingPurpleHeartDocument();
        return phd != null ? phd.getAcceptable() : null;
    }
	/**
	 * Gets the purple heart status for the given person.
	 */
	public String getPurpleHeartStatus( Person person ) {

		PurpleHeart purpleHeart = person != null ? person.getPurpleHeart() : null;
		DecorationStatus status = purpleHeart != null ? purpleHeart.getStatus() : null;
		return status != null ? status.getCode() : null;
	}

	/*
	 * (non-Javadoc)
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPurpleHeartIndicator(gov.va.med.esr.common.model.person.Person)
	 */
	public String getPurpleHeartIndicator( Person person ) {
		
		PurpleHeart purpleHeart = (person != null) ? person.getPurpleHeart() : null;
		Boolean indicator = purpleHeart != null ? purpleHeart.getPhIndicator() : null;
		
		String flag = null;
		if( indicator != null ) {
			flag = Boolean.TRUE.equals( indicator ) ? YES_INDICATOR : NO_INDICATOR;
		}
		return flag;
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setPHDocumentAcceptableIndicator(java.lang.String)
	 */
	public void setPHDocumentAcceptableIndicator(String indicator) {
        // Apply change to incoming, update the onfile later
		if( indicator != null ) {
			PurpleHeart ph = this.getIncomingPurpleHeart();
			if (ph != null) {
				PurpleHeartDocument document = getLatestPurpleHeartDocument();
				if (document == null) {
					document = new PurpleHeartDocument();
					ph.addDocument(document);
				}
				document.setAcceptable( YES_INDICATOR.equals( indicator ) ? Boolean.TRUE : Boolean.FALSE );				
			}
		}
	}	
	
	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setAssignedContactUser(java.lang.String)
	 */
	public void setAssignedContactUser(String user) throws RuleException {
		PurpleHeart purpleHeart = this.getIncomingPerson().getPurpleHeart();
		if (purpleHeart != null) {
			purpleHeart.setAssignedContactUser(user);
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setDocumentType(java.lang.String)
	 */
	public void setDocumentType(String documentType) throws RuleException {
		PurpleHeartDocument doc = getOrCreatePHDocument(this.getIncomingPerson().getPurpleHeart());
		if (doc != null && documentType != null) {
			try {
				doc.setDocumentType((PHDocumentType)getLookupService().getByCode(PHDocumentType.class, documentType));
			}
			catch (ServiceException e) {
				throw new RuleException("Failed to set Purple Heart Document Type");
			}			
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setPHDocumentDataSource(java.lang.String)
	 */
	public void setPHDocumentDataSource(String dataSource) throws RuleException {
		PurpleHeartDocument doc = getOrCreatePHDocument(this.getIncomingPerson().getPurpleHeart());
		if (doc != null && dataSource != null) {
			try {
				doc.setDataSource((PHDataSource)getLookupService().getByCode(PHDataSource.class, dataSource));
			}
			catch (ServiceException e) {
				throw new RuleException("Failed to set Purple Heart Document Data Source");
			}			
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setPHDocumentReceivedDate(java.util.Date)
	 */
	public void setPHDocumentReceivedDate(Date receivedDate) {
		PurpleHeartDocument doc = getOrCreatePHDocument(this.getIncomingPerson().getPurpleHeart()); 
		if (doc != null) {
			doc.setReceivedDate(receivedDate);
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setPHFacilityByCode(java.lang.String)
	 */
	public void setPHFacilityByCode(String facilityCode) throws RuleException {
		PurpleHeart purpleHeart = this.getIncomingPerson().getPurpleHeart();
		if (purpleHeart != null && facilityCode != null) {
			try {
				purpleHeart.setFacility(getLookupService().getVaFacilityByCode(facilityCode));
			}
			catch (ServiceException e) {
				throw new RuleException("Failed to set PH Facility");
			}						
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#setPHLastUpdatedByUser(java.lang.String)
	 */
	public void setPHLastUpdatedByUser(String user) throws RuleException {
		PurpleHeart purpleHeart = this.getIncomingPerson().getPurpleHeart();
		if (purpleHeart != null) {
			purpleHeart.setStatusLastUpdateUser(user);
		}
	}

	/**
	 * @see gov.va.med.esr.common.rule.PurpleHeartInput#getPHDocReceivedDateFromMSDSmessage()
	 */
	public Date getPHDocReceivedDateFromMSDSmessage() {
		// Notice this method s/b used only in MSDS context. There will be only one document.
		// The MSDS rules add a PH from MSDS ONLY when there are no onfile PH. For convenience,
		// the PH/doc are used to transport the indicator and the received date from the MSDS message.
		// There will be only one doc from MSDS.
		PurpleHeart purpleHeart = this.getIncomingPerson().getPurpleHeart();
		PurpleHeartDocument doc = getOrCreatePHDocument(purpleHeart);   
		return (doc != null) ? doc.getReceivedDate() : null;
	}	
	
	private PurpleHeartDocument getOrCreatePHDocument(PurpleHeart purpleHeart) {
		// There will be only one doc from MSDS.
		Set docs = (purpleHeart != null) ? purpleHeart.getDocuments() : new HashSet(); 
		PurpleHeartDocument doc = (docs.size() > 0) ? (PurpleHeartDocument)docs.iterator().next() : null;
		if (purpleHeart != null && doc == null) {
			doc = new PurpleHeartDocument();
			purpleHeart.addDocument(doc);
		}
		return doc;
	}
	
	
	/**
	 * Gets the incoming person purple heart.
	 */
	private PurpleHeart getIncomingPurpleHeart() {
		Person incoming = this.getIncomingPerson();
		return incoming.getPurpleHeart();
	}

	/**
	 * Gets the result person purple heart. 
	 */
	private PurpleHeart getResultPurpleHeart() {
		Person result = this.getResultPerson();
		return result.getPurpleHeart();
	}
        
    private Person getPriorPersonForPurpleHeart() throws RuleException {
        return this.getPriorEEPerson();
    }    
    
    private PHInputData getPHInputData() {
        RuleDataAware ruleDataAware = this.getRuleDataAware();
        if (ruleDataAware instanceof PHInputData) {
            return (PHInputData) ruleDataAware;
        }
        return null;
    }
    
    private PurpleHeartDocument getIncomingPurpleHeartDocument() {
        return this.getPHInputData() != null ? 
                this.getPHInputData().getIncomingPurpleHeartDocument() : null;        
    }
    
    /**
     * if any acceptable document is found return true
	 * else if non-acceptable document is found return false
	 * if the indicator is null return null
     * @param person
     * @return
     */
    public Boolean isPHDocumentAcceptable(Person person) {
    	Boolean docAcceptable = null;
        PurpleHeart ph = (person != null) ? person.getPurpleHeart() : null;
        Set docs = ph != null ? ph.getDocuments() : null;
        if (docs != null && docs.size() > 0) {
            for (Iterator iter = docs.iterator(); iter.hasNext();) {
                PurpleHeartDocument phd = (PurpleHeartDocument)iter.next();
                if (phd.getAcceptable() != null) {
                	docAcceptable = phd.getAcceptable();
                	if (docAcceptable.booleanValue())
                		return docAcceptable;
                }
            }
        }

        return docAcceptable;
    }   
    
    public Boolean getFirstAssessedDocumentAcceptable() {
    	PurpleHeart ph = getIncomingPurpleHeart();
    	if (ph != null) {
	    	List documents = new ArrayList(ph.getDocuments ());
	    	if (documents != null && documents.size() > 0) {    		
	    		Collections.sort(documents);
	    		for (int i=0; i<documents.size(); i++) {
	    			//get the first document with non-null acceptable indicator
	    			PurpleHeartDocument doc = (PurpleHeartDocument)documents.get(i);
	    			if (doc.getAcceptable() != null)
	    				return doc.getAcceptable();
	    		}
	    	}
    	}
    	//No document is assed yet    	
    	return null;
    }
    
    public Boolean getSecondAssessedDocumentAcceptable() {
    	PurpleHeart ph = getIncomingPurpleHeart();
    	if (ph != null) { 
	    	List documents = new ArrayList(ph.getDocuments ());
	    	Boolean firstDocAcceptable = null;
	    	if (documents != null && documents.size() > 0) {    		
	    		Collections.sort(documents);
	    		for (int i=0; i<documents.size(); i++) {
	    			//get the first document with non-null acceptable indicator
	    			PurpleHeartDocument doc = (PurpleHeartDocument)documents.get(i);
	    			if (doc.getAcceptable() != null) {
	    				if (firstDocAcceptable == null) {
	    					firstDocAcceptable = doc.getAcceptable();
	    				}
	    				else {
	    					return doc.getAcceptable(); 
	    				}
	    			}
	    		}
	    	}
    	}
    	//2nd document is not assesed yet    	
    	return null;
    }
    private PurpleHeartDocument getAcceptablePHDocument(Person person) {
        PurpleHeart ph = (person != null) ? person.getPurpleHeart() : null;
        Set docs = ph != null ? ph.getDocuments() : null;
        if (docs != null && docs.size() > 0) {
            // Find any acceptable document
            for (Iterator iter = docs.iterator(); iter.hasNext();) {
                PurpleHeartDocument phd = (PurpleHeartDocument)iter.next();
                if (phd.getAcceptable() != null && phd.getAcceptable().booleanValue()) {
                    return phd;
                }
            }
        }

        return null;
    }    
    
    private PurpleHeartDocument getLatestPurpleHeartDocument() {
        if ( resultPurpleHeartDocument == null ) {
            this.resultPurpleHeartDocument = this.initLatestPurpleHeartDocument();
        }
        return this.resultPurpleHeartDocument;
    }
    
    private PurpleHeartDocument initLatestPurpleHeartDocument() {
        PurpleHeart ph = this.getIncomingPurpleHeart();
        PurpleHeartDocument latest = null;        
        if (ph != null) {
            // Only one document will be new or updated. Find the new one
            // or the most recent one.
            Set docs = ph != null ? ph.getDocuments() : null;
            if (docs != null) {
	            for (Iterator iter = docs.iterator(); iter.hasNext();) {
	                PurpleHeartDocument phd = (PurpleHeartDocument) iter.next();
	                if (phd.getEntityKey() == null || phd.getCreatedOn() == null) {
	                    return phd;
	                }
	                // Prime the latest
	                if (latest == null) {
	                    latest = phd;
	                } else if (latest.getModifiedOn() != null
	                        && this.isAfter(phd.getModifiedOn(), latest
	                                .getModifiedOn())) {
	                    return phd;
	                }
	            }
            }
        }
        return latest;
    }
    
}