package gov.va.med.esr.service.impl;

// Java Classes
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.PersonMergeInfo;
import gov.va.med.esr.common.model.person.PersonUnmergeInfo;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.common.persistent.person.PersonDAO;
import gov.va.med.esr.common.persistent.person.PersonMergeDAO;
import gov.va.med.esr.common.persistent.person.PersonUnmergeDAO;
import gov.va.med.esr.service.EligibilityEnrollmentService;
import gov.va.med.esr.service.PSDelegateService;
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.esr.service.PersonMergeService;
import gov.va.med.esr.service.PersonMergeWorklistSearchQueryInfo;
import gov.va.med.esr.service.PersonSearchQueryInfo;
import gov.va.med.esr.service.PersonService;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.pagination.SearchQueryInfo;

//Java Classes
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.Map;


import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.Validate;

/**
 * Business service for person merge.
 * 
 * @author DNS   CHENB
 * @author Andrew Pach
 */
public class PersonMergeServiceImpl extends AbstractRuleAwareServiceImpl
		implements PersonMergeService {

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

	/**
	 * Added for CR_7382
	 */
	public PSDelegateService delegateService = null;

	public PSDelegateService getDelegateService() {
		return delegateService;
	}

	public void setDelegateService(PSDelegateService service) {
		this.delegateService = service;
	}

	private PersonService personService = null;
	/**
	 * An instance of personDAO
	 */
	private PersonDAO personDAO = null;

	/**
	 * An instance of personMergeDAO
	 */
	private PersonMergeDAO personMergeDAO = null;

	/**
	 * An instance of personUnmergeDAO
	 */
	private PersonUnmergeDAO personUnmergeDAO = null;

	private String eligibilityEnrollmentServiceName = null;

	/**
	 * Instance of EligibilityEnrollmentService
	 */
	private EligibilityEnrollmentService eligibilityEnrollmentService = null;

	/**
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull(personDAO, "Missing required personDAO");
		Validate.notNull(personMergeDAO, "Missing required personMergeDAO");
		Validate.notNull(personUnmergeDAO, "Missing required personUnmergeDAO");
	}

	/**
	 * Default constructor.
	 */
	public PersonMergeServiceImpl() {
		super();
	}

	/**
	 * @see gov.va.med.esr.service.PersonMergeService#getPersonMergeInfo(gov.va.med.fw.model.EntityKey)
	 */
	public PersonMergeInfo getPersonMergeInfo(EntityKey personMergeInfoEntityKey)
			throws ServiceException {
		PersonMergeInfo info = null;
		try {
			info = (PersonMergeInfo) personMergeDAO
					.getByKey(personMergeInfoEntityKey);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to get PersonMergeInfo for: "
					+ personMergeInfoEntityKey.toString(), ex);
		}
		if (info != null) {
			fillPersonIdentityTraits(info);
		}
		return info;
	}

	/**
	 * Fills in the identity traits onto the person merge info.
	 * 
	 * @param info
	 *            The person merge info.
	 * @throws ServiceException
	 *             if any problems were encountered.
	 */
	private void fillPersonIdentityTraits(PersonMergeInfo info)
			throws ServiceException {
		try {
			PersonIdEntityKey key1 = info.getPrimaryPersonEntityKey();
			VPIDEntityKey vpid1 = personDAO.getVPIDByPersonId(key1);
			info.setPrimaryPersonIdentityTraits(this.getPsDelegateService()
					.getIdentityTraits(vpid1));

			PersonIdEntityKey key2 = info.getDeprecatedPersonEntityKey();
			VPIDEntityKey vpid2 = personDAO.getVPIDByPersonId(key2);
			info.setDeprecatedPersonIdentityTraits(getDeprecatedIdentityTraits(
					vpid1, vpid2));
		} catch (DAOException e) {
			throw new ServiceException(
					"Failed to convert PersinIDEntityKey with VPIDEntityKey: "
							+ info.toString(), e);
		}
	}

	/**
	 * Gets the deprecated identity traits for the passed in surviving and
	 * deprecated VPID information.
	 * 
	 * @param survivingVPID
	 *            The surviving VPID Id
	 * @param deprecatedVPID
	 *            The deprecated VPID Id.
	 * @return The deprecated traits
	 * @throws ServiceException
	 *             if any problems were encountered.
	 */
	private PersonIdentityTraits getDeprecatedIdentityTraits(
			VPIDEntityKey survivingVPID, VPIDEntityKey deprecatedVPID)
			throws ServiceException {
		Validate.notNull(survivingVPID, "Surviving VPID can not be null.");
		Validate.notNull(deprecatedVPID, "Deprecated VPID can not be null.");
		List history = null;
		try {
			history = this.getPsDelegateService()
					.getIdentityTraitsUpdateHistory(survivingVPID);
		} catch (ServiceException e) {
			throw new ServiceException(
					"Failed to deprecated PersonIdentityTraits when calling getIdentityTraitsUpdateHistory for: "
							+ survivingVPID.toString(), e);
		}

		for (int i = 0; history != null && i < history.size(); i++) {
			PersonIdentityTraits traits = (PersonIdentityTraits) history.get(i);
			if (traits != null && traits.isDeprecated()
					&& deprecatedVPID.equals(traits.getVpid()))
				return traits;
		}
		return null;
	}

	/**
	 * @see gov.va.med.esr.service.PersonMergeService#updatePerson(gov.va.med.esr.common.model.person.Person)
	 */
	public Person updatePerson(Person incoming) throws ServiceException {
		Validate.notNull(incoming, "A veteran must not be null");
		Person onFile = this.getPersonService().getPerson(
				(PersonEntityKey) incoming.getEntityKey());
		boolean dataIsFromUI = true;

		// Merge data
		Person merged = this.getMergeRuleService().mergePerson(incoming,
				onFile, dataIsFromUI);
		Person calculated = this.getEligibilityEnrollmentService()
				.assessEEImpact(merged, dataIsFromUI, false);
		this.getEventRuleService().handleCommonPostEvents(calculated,
				dataIsFromUI);

		// Mark this person merge info as completed.
		try {
			PersonMergeInfo info = personMergeDAO
					.getPersonMergeInfo((PersonIdEntityKey) calculated
							.getPersonEntityKey());
			if (info != null) {
				// Unlock the record
				info.setRecordLocked(Boolean.FALSE);

				// Update the start date
				updateStartDateIfNeeded(info);

				// Update the completed date
				info.setMergeEndDate(new Date(getTimestampManager()
						.getTransactionTimestamp().getTime()));

				// Update the person merge info
				updatePersonMergeInfo(info);
			}
		} catch (DAOException ex) {
			throw new ServiceException(
					"Failed to delete PersonMergeInfo related to: "
							+ incoming.getPersonEntityKey().toString(), ex);
		}

		// Save the merged person
		return getPersonService().save(calculated);
	}

	/**
	 * @see gov.va.med.esr.service.PersonMergeService#deletePersonMergeInfo(gov.va.med.esr.common.model.person.PersonMergeInfo)
	 */
	public void deletePersonMergeInfo(PersonMergeInfo info)
			throws ServiceException {
		try {
			personMergeDAO.removeObject(info.getEntityKey());
		} catch (DAOException e) {
			throw new ServiceException("Failed to delete PersonMergeInfo: "
					+ info.toString(), e);
		}
	}

	/**
	 * @see gov.va.med.esr.service.PersonMergeService#getPersonMergeInfo(gov.va.med.esr.common.model.person.id.PersonIdEntityKey)
	 */
	public PersonMergeInfo getPersonMergeInfo(
			PersonIdEntityKey primaryPersonIdEntityKey) throws ServiceException {
		PersonMergeInfo info = null;
		try {
			info = (PersonMergeInfo) personMergeDAO
					.getPersonMergeInfo(primaryPersonIdEntityKey);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to get PersonMergeInfo for: "
					+ primaryPersonIdEntityKey.toString(), ex);
		}
		if (info != null) {
			fillPersonIdentityTraits(info);
		}
		return info;
	}
    
    /**
     * @see gov.va.med.esr.service.PersonMergeService#getPersonMergeDataInfo(gov.va.med.esr.common.model.person.id.PersonIdEntityKey)
     */
    public PersonMergeInfo getPersonMergeDataInfo(
            PersonIdEntityKey primaryPersonIdEntityKey) throws ServiceException {
        PersonMergeInfo info = null;
        try {
            info = (PersonMergeInfo) personMergeDAO
                    .getPersonMergeInfo(primaryPersonIdEntityKey);
        } catch (DAOException ex) {
            throw new ServiceException("Failed to get PersonMergeInfo for: "
                    + primaryPersonIdEntityKey.toString(), ex);
        }
        
        return info;
    }
    
	/**
	 * @see gov.va.med.esr.service.PersonMergeService#hasActiveMerge(PersonIdEntityKey)
	 */
	public boolean hasActiveMerge(PersonIdEntityKey primaryPersonIdEntityKey)
			throws ServiceException {
		PersonMergeInfo info = null;
		boolean hasActiveMerge = false;
		try {
			info = (PersonMergeInfo) personMergeDAO
					.getPersonMergeInfo(primaryPersonIdEntityKey);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to get PersonMergeInfo for: "
					+ primaryPersonIdEntityKey.toString(), ex);
		}
		if (info != null) {
			if (info.isRecordLocked() != null) {
				hasActiveMerge = info.isRecordLocked().booleanValue();
			}
		}

		return hasActiveMerge;
	}

	/**
	 * @see gov.va.med.esr.service.PersonMergeService#updatePersonMergeInfo(gov.va.med.esr.common.model.person.PersonMergeInfo)
	 */
	public PersonMergeInfo updatePersonMergeInfo(PersonMergeInfo info)
			throws ServiceException {
		return updatePersonMergeInfoImpl(info, false);
	}
	
	/**
	 * @see gov.va.med.esr.service.PersonMergeService#updatePersonMergeInfoByPrimaryDepIDs(gov.va.med.esr.common.model.person.id.PersonEntityKey,
	 * gov.va.med.esr.common.model.person.id.PersonEntityKey)
	 */
	public PersonMergeInfo updatePersonMergeInfoByPrimaryDepIDs(PersonEntityKey primaryId, PersonEntityKey deprecatedId)
		throws ServiceException {

		
		PersonMergeInfo info = null;
		// Mark this person merge info as completed.
		try {

			List results = personMergeDAO.findByPrimaryDeprecatedIds((PersonIdEntityKey)primaryId, 
					(PersonIdEntityKey)deprecatedId);

			if (results != null) {			
				
					for (int i = 0; i < results.size(); i++) {						
						info = (PersonMergeInfo)results.get(i);
						
						if (info != null) {
							// Unlock the record
							info.setRecordLocked(Boolean.FALSE);
			
							// Update the start date
							updateStartDateIfNeeded(info);
			
							// Update the completed date
							info.setMergeEndDate(new Date(getTimestampManager()
									.getTransactionTimestamp().getTime()));
			
							// Update the person merge info
							updatePersonMergeInfo(info);	
						}
					}
			}
		} catch (DAOException ex) {
			throw new ServiceException(
					"Failed to update PersonMergeInfo related to: "+ ((info != null) ? info.toString() : ""), ex);
		}

		return info;
	}
	   	
	
	/**
	 * @see gov.va.med.esr.service.PersonMergeService#saveInProgress(gov.va.med.esr.common.model.person.PersonMergeInfo)
	 */
	public PersonMergeInfo saveInProgress(PersonMergeInfo info)
			throws ServiceException {
		updateStartDateIfNeeded(info);
		return updatePersonMergeInfoImpl(info, true);
	}

	/**
	 * Updates the person merge info.
	 * 
	 * @param info
	 *            The person merge info
	 * @param ensureEntityChanged
	 *            If true, the person merge info will be checked to ensure the
	 *            entity changed
	 * @return The updated person merge info
	 * @throws ServiceException
	 *             if any problems were encountered
	 */
	private PersonMergeInfo updatePersonMergeInfoImpl(PersonMergeInfo info,
			boolean ensureEntityChanged) throws ServiceException {
		try {
			if (ensureEntityChanged) {
				// Get the on-file info
				PersonMergeInfo onFilePersonMergeInfo = getPersonMergeInfo(info
						.getEntityKey());

				// Ensure that something changed on the incoming entity as
				// compared to the onFile entity
				ensureEntityChanged(info, onFilePersonMergeInfo);

				// Evict the on-file entity since we aren't overlaying data onto
				// it
				personMergeDAO.evict(onFilePersonMergeInfo);
			}

			// Perform the update
			personMergeDAO.update(info);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to update PersonMergeInfo: "
					+ info.toString(), ex);
		}

		return this.getPersonMergeInfo(info.getEntityKey());
	}

	/**
	 * Updates the merge start date if it hasn't been set yet.
	 * 
	 * @param info
	 *            The person merge info
	 */
	public void updateStartDateIfNeeded(PersonMergeInfo info) {
		// If this is the first merge in progress, set the date
		if (!info.isMergeInProgress()) {
			info.setMergeStartDate(new Date(getTimestampManager()
					.getTransactionTimestamp().getTime()));
		}
	}

	public boolean hasEnrollmentData(VPIDEntityKey vpid) {
		boolean hasData = true;
		EnrollmentDetermination ed = null;
		try {
			ed = personDAO.getByVPID(vpid).getEnrollmentDetermination();
		} catch (DAOException daoe) {
			logger.error(
					"Exception occured while retrieving the person with VPID = "
							+ vpid, daoe);
		}
		if (ed == null) {
			hasData = false;
		}
		return hasData;
	}

	/**
	 * Process and store PeronMerge request from external. If there is a record
	 * in Person_Merge with same Primary and Deprecated, then do nothing. If
	 * there is a record in Person_Merge with fliped Primary and Deprecated,
	 * then replace it with new mergeInfo. If there is a record in
	 * Person_Unmerge for both PersonIds, then remove it from Person_Unmerge and
	 * store the new merge_info.
	 * 
	 * @see gov.va.med.esr.service.PersonMergeService#processPersonMergeInfo(gov.va.med.esr.common.model.person.PersonMergeInfo)
	 */
	public void processPersonMergeInfo(PersonMergeInfo info,
			VPIDEntityKey deprecatedVPID, VPIDEntityKey survivingVPID)
			throws ServiceException {
		try {
			/**
			 * Added for CR_7382 this will check if the Primary or Deprecated
			 * user is either a System User or Health care user and will do
			 * nothing if it is true
			 */
		    //For CCR 11403:
		    //NOT BE ABLE TO REPLACE THE OBTAIN() CALL HERE BECAUSE IdM Web Service 1306 response does not have category data
		    //Cory verified that event the current ejb obtain() call, in his own work:
		    //"I’m not sure this ever brought you value, as the obtain call you are making returns the Primary view, and the primary view doesn’t currently have “Categories”.  Meaning isSystemOrHealthCareUser would always be null"
		    //Danny confirmed, "MVI currently has only patient population,"
		    //So the references to isSystemOrHealthCareUser will be commented out
/*			if (getDelegateService().isSystemOrHealthCareUser(survivingVPID)) {
				// If Primary person is a System User or Health care provider
				// then do not add the data into person merge
				return;
			} else if (getDelegateService().isSystemOrHealthCareUser(
					deprecatedVPID)) {
				// If Deprecated Person is a System User or Health care provider
				// then do not add the data into person merge
				return;
			}*/
			
			// Fix for CR_8255 If neither person has enrollment data then do not
			// merge.
			if (!hasEnrollmentData(survivingVPID)) {
				if (!hasEnrollmentData(deprecatedVPID)) {
					return;
				}
			}
			// Remove unmerge record if one exists for these id's
			PersonUnmergeInfo existUnmergeInfo = personUnmergeDAO
					.findByPersonIds(info.getPrimaryPersonEntityKey(), info
							.getDeprecatedPersonEntityKey());
			if (existUnmergeInfo != null) {
				personUnmergeDAO.removeObject(existUnmergeInfo.getEntityKey());
			}

			// See if a person merge record already exists
			PersonMergeInfo existInfo = personMergeDAO.findByPersonIds(info
					.getPrimaryPersonEntityKey(), info
					.getDeprecatedPersonEntityKey());
			if (existInfo != null) {
				if (existInfo.getPrimaryPersonEntityKey().equals(
						info.getDeprecatedPersonEntityKey())) {
					// Remove the old person merge info since the primary and
					// deprecated keys were swapped
					deletePersonMergeInfo(existInfo);
				} else {
					if (existInfo.getPrimaryPersonEntityKey().equals(
							info.getPrimaryPersonEntityKey())) {
						// The correct person merge info record already exists
						// so do nothing
						return;
					}
				}
			}
			// Update the person merge info
			updatePersonMergeInfo(info);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to save PersonMergeInfo: "
					+ info.toString(), ex);
		}
	}

	/**
	 * Searches and returns a list of PersonMergeInfo objects.
	 * 
	 * @param searchQueryInfo
	 *            The search criteria
	 * 
	 * @return The list of PersonMergeInfo objects
	 * @throws ServiceException
	 *             if any problems were encountered.
	 */
    public List search(SearchQueryInfo searchQueryInfo) throws ServiceException
    {
        
        if (searchQueryInfo != null && searchQueryInfo instanceof PersonMergeWorklistSearchQueryInfo)
        {
            return searchByPersonMergeWorklistSearchQueryInfo((PersonMergeWorklistSearchQueryInfo) searchQueryInfo);
        }
        
        List results = null;
        try
        {
            results = personMergeDAO.loadAllNotCompleted(searchQueryInfo);
            if (results == null)
            {
                results = new ArrayList();
            }
        }
        catch (DAOException ex)
        {
            throw new ServiceException("Failed to loadAll PersonMergeInfo objects from the DAO.", ex);
        }

        HashMap personIdMap = new HashMap();
        for (int i = 0; i < results.size(); i++)
        {
            Object obj = results.get(i);
            if (obj != null && (obj instanceof PersonMergeInfo))
            {
                PersonMergeInfo info = (PersonMergeInfo)obj;
                PersonIdEntityKey personId1 = info.getPrimaryPersonEntityKey();
                try
                {
                    VPIDEntityKey vpid1 = personDAO.getVPIDByPersonId(personId1);
                    personIdMap.put(personId1, vpid1);
                }
                catch (DAOException ex)
                {
                    throw new ServiceException("Failed to getVPIDByPersonId from the DAO.", ex);
                }
            }
            //calling psDelegateService one by one is expensive
            //this.fillPersonIdentityTraits((PersonMergeInfo)results.get(i));
        }
        
        Map traits = null;

        try
        {
            traits = this.getPsDelegateService().getIdentityTraits(personIdMap.values());
            
        }
        catch(ServiceException se)
        {
            //just log the exception and continue. This could be a timeout from PSIM, if it is the case try to 
            // get them one by one below.
            logger.error("PSIM service Exception while getIdentityTraits(list).", se);
        }
        
        for (int i = 0; i < results.size(); i++)
        {
            Object obj = results.get(i);
           
            if (obj != null && (obj instanceof PersonMergeInfo))
            {
                PersonMergeInfo info = (PersonMergeInfo)obj;
                PersonIdEntityKey personId1 = info.getPrimaryPersonEntityKey();
                VPIDEntityKey vpid1 = (VPIDEntityKey)personIdMap.get(personId1);
                PersonIdentityTraits identityTraits =  null;
                
                if ( traits != null)
                {
                    identityTraits = (PersonIdentityTraits)traits.get(vpid1.getVPID());
                }
                
                // failed to get the list from psim call , do it again now one by one if it fails here
                // I am not trying any more :)
                try
                {
                    if ( identityTraits == null )
                    {
                        identityTraits = getPsDelegateService().getIdentityTraits(vpid1);
                    }
                }
                catch(ServiceException se)
                {
                    logger.error("PSIM service Exception while getIdentityTraits(vpid).", se);
                }
                info.setPrimaryPersonIdentityTraits(identityTraits);

                PersonIdEntityKey personId2 = info.getDeprecatedPersonEntityKey();
                try
                {
                    VPIDEntityKey vpid2 = personDAO.getVPIDByPersonId(personId2);
                    info.setDeprecatedPersonIdentityTraits(getDeprecatedIdentityTraits(vpid1, vpid2));
                }
                catch (DAOException ex)
                {
                    throw new ServiceException("Failed to getVPIDByPersonId from the DAO.", ex);
                }

            }
            
        }

        searchQueryInfo.setSortPerformed(true);

        return results;
    }

   
    private List searchByPersonMergeWorklistSearchQueryInfo(PersonMergeWorklistSearchQueryInfo personMergeWorklistSearchQueryInfo) throws ServiceException {

		// copy criteria from the person merge search query object to a person
		// search query info object
		PersonSearchQueryInfo personSearchQueryInfo = new PersonSearchQueryInfo();
		try {
			BeanUtils.copyProperties(personSearchQueryInfo,
					personMergeWorklistSearchQueryInfo);
		} catch (IllegalAccessException e) {
			throw new ServiceException(e);
		} catch (InvocationTargetException e) {
			throw new ServiceException(e);
		}

		List results = new ArrayList();
        personMergeWorklistSearchQueryInfo.setSortPerformed(false);
        personMergeWorklistSearchQueryInfo.setTotalNumberOfEntries(results.size());
        personMergeWorklistSearchQueryInfo.setSearchTypePerformed(SearchQueryInfo.SEARCH_READ_ALL);

		// find veterans that match the search criteria specified
		List personList = personService.search(personSearchQueryInfo);
		if (personList.size() > 0) {
			Iterator personIterator = personList.iterator();
			List personEntityKeyList = new ArrayList();
			Hashtable personEntityKeyHashTable = new Hashtable();

			// for each veteran found
			while (personIterator.hasNext()) {
				// get the person id and store in a list
				Person person = (Person) personIterator.next();
				personEntityKeyList.add(person.getPersonEntityKey());
				personEntityKeyHashTable.put(person.getPersonEntityKey()
						.getKeyValueAsString(), person);
			}

			try {
				// find all person merge objects whose primary person is
				// associated
				// with an id in the list
				results = personMergeDAO
						.findNotCompletedByPrimaryPersonEntityKeys(
								personEntityKeyList, personMergeWorklistSearchQueryInfo);

			} catch (DAOException ex) {
				throw new ServiceException(
						"Failed to find PersonMergeInfo objects from the DAO.",
						ex);
			}
			Iterator resultsIterator = results.iterator();

			// for each result found
			while (resultsIterator.hasNext()) {
				PersonMergeInfo personMergeInfo = (PersonMergeInfo) resultsIterator
						.next();

				// if the primary person is in the list of persons returned from
				// the person search
				if (personEntityKeyHashTable.containsKey(personMergeInfo
						.getPrimaryPersonEntityKey().getKeyValueAsString())) {
					// add to merge info object
					Person person = (Person) personEntityKeyHashTable
							.get(personMergeInfo.getPrimaryPersonEntityKey()
									.getKeyValueAsString());
					personMergeInfo.setPrimaryPerson(person);
				} else {
					// else
					// lookup the person and add to the merge info object
					VPIDEntityKey vpid = personService
							.getVPIDByPersonId(personMergeInfo
									.getPrimaryPersonEntityKey());

					PersonSearchQueryInfo personSearchQueryInfoPerson = new PersonSearchQueryInfo();
					personSearchQueryInfoPerson
							.setSearchOptimizationType(SearchQueryInfo.SEARCH_READ_ALL);
					personSearchQueryInfoPerson.setRemoveEmptyStrings(true);
					personSearchQueryInfoPerson
							.setSortElements(personMergeWorklistSearchQueryInfo
									.getSortElements());
					personSearchQueryInfoPerson.setVpid(vpid.getVPID());
					List personResults = personService
							.search(personSearchQueryInfoPerson);
					Person person = (Person) personResults.get(0);
					personMergeInfo.setPrimaryPerson(person);
				}

				// if the deprecated person is in the list of persons returned
				// from the person search
				if (personEntityKeyHashTable.containsKey(personMergeInfo
						.getDeprecatedPersonEntityKey().getKeyValueAsString())) {
					// add to merge info object
					Person person = (Person) personEntityKeyHashTable
							.get(personMergeInfo.getDeprecatedPersonEntityKey()
									.getKeyValueAsString());
					personMergeInfo.setDeprecatedPerson(person);
				} else {
					// else
					// lookup the person and add to the merge info object
					VPIDEntityKey vpid = personService
							.getVPIDByPersonId(personMergeInfo
									.getDeprecatedPersonEntityKey());

					PersonSearchQueryInfo personSearchQueryInfoPerson = new PersonSearchQueryInfo();
					personSearchQueryInfoPerson
							.setSearchOptimizationType(SearchQueryInfo.SEARCH_READ_ALL);
					personSearchQueryInfoPerson.setRemoveEmptyStrings(true);
					personSearchQueryInfoPerson
							.setSortElements(personMergeWorklistSearchQueryInfo
									.getSortElements());
					personSearchQueryInfoPerson.setVpid(vpid.getVPID());
					List personResults = personService
							.search(personSearchQueryInfoPerson);
					Person person = (Person) personResults.get(0);
					personMergeInfo.setDeprecatedPerson(person);
				}
			}
		}

		return results;
	}

	/**
	 * @return Returns the personMergeDAO.
	 */
	public PersonDAO getPersonDAO() {
		return personDAO;
	}

	/**
	 * @param personDAO
	 *            The personMergeDAO to set.
	 */
	public void setPersonDAO(PersonDAO personDAO) {
		this.personDAO = personDAO;
	}

	/**
	 * @return Returns the personMergeDAO.
	 */
	public PersonMergeDAO getPersonMergeDAO() {
		return personMergeDAO;
	}

	/**
	 * @param personMergeDAO
	 *            The personMergeDAO to set.
	 */
	public void setPersonMergeDAO(PersonMergeDAO personMergeDAO) {
		this.personMergeDAO = personMergeDAO;
	}

	/**
	 * @return Returns the personUnmergeDAO.
	 */
	public PersonUnmergeDAO getPersonUnmergeDAO() {
		return personUnmergeDAO;
	}

	/**
	 * @param personUnmergeDAO
	 *            The personUnmergeDAO to set.
	 */
	public void setPersonUnmergeDAO(PersonUnmergeDAO personUnmergeDAO) {
		this.personUnmergeDAO = personUnmergeDAO;
	}

	/**
	 * @return Returns the eligibilityEnrollmentServiceName.
	 */
	public String getEligibilityEnrollmentServiceName() {
		return eligibilityEnrollmentServiceName;
	}

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

	/**
	 * @return Returns the EligibilityEnrollmentService.
	 */
	public EligibilityEnrollmentService getEligibilityEnrollmentService() {
		if (this.eligibilityEnrollmentService == null)
			this.eligibilityEnrollmentService = (EligibilityEnrollmentService) getApplicationContext()
					.getBean(this.getEligibilityEnrollmentServiceName(),
							EligibilityEnrollmentService.class);
		return this.eligibilityEnrollmentService;
	}

	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}
	
	public boolean hasDeprecatedRecord(PersonIdEntityKey deprecatedPersonIdEntityKey)
	throws ServiceException {
		PersonMergeInfo info = null;
		boolean deprecated = false;
		
		try {
			info = (PersonMergeInfo) personMergeDAO.getPersonMergeInfoByDeprecatedId(deprecatedPersonIdEntityKey);
		} catch (DAOException ex) {
			throw new ServiceException("Failed to get PersonMergeInfo for: "
					+ deprecatedPersonIdEntityKey.toString(), ex);
		}
		
		return info == null ? false : true;
	}
}
