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

// Java Classes
import gov.va.med.esr.common.batchprocess.SSASSNVerificationData;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.comms.CommsLogEntry;
import gov.va.med.esr.common.model.comms.HandBookMailQueue;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.financials.IncomeTestStatus;
import gov.va.med.esr.common.model.lookup.Relationship;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.lookup.AddressType;
import gov.va.med.esr.common.model.lookup.ConfidentialAddressCategoryType;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.Relation;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.SSNVerification;
import gov.va.med.esr.common.model.person.SSNVerificationDetail;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.common.model.security.ESRUserPrincipalImpl;
import gov.va.med.esr.common.persistent.demographic.AddressDAO;
import gov.va.med.esr.common.persistent.demographic.ConfidentialAddressCategoryDAO;
import gov.va.med.esr.common.persistent.demographic.ConfidentialAddressCategoryTypeDAO;
import gov.va.med.esr.common.persistent.history.HistoryDAO;
import gov.va.med.esr.common.persistent.person.SSNVerificationDetailDAO;
import gov.va.med.esr.common.rule.service.ContactInfoRuleService;
import gov.va.med.esr.common.rule.service.DemographicRuleService;
import gov.va.med.esr.common.rule.service.EventRuleService;
import gov.va.med.esr.common.util.MailingAddressHelper;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.esr.service.EligibilityEnrollmentService;
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.esr.service.UnknownLookupCodeException;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.service.external.demographics.DemographicsChangeEvent;
import gov.va.med.esr.service.external.demographics.DemographicsChangeSummary;
import gov.va.med.esr.service.external.demographics.DemographicsChangeType;
import gov.va.med.esr.service.trigger.ProcessTriggerEvent;
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.persistent.DAOOperations;
import gov.va.med.fw.persistent.hibernate.AbstractDAOAction;
import gov.va.med.fw.service.EntityNotChangedException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.trigger.TriggerEvent;
import gov.va.med.fw.service.trigger.TriggerRouter;
import gov.va.med.fw.util.ObjectUtils;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.validation.ValidationServiceException;
import gov.va.med.esr.common.model.party.ConfidentialAddressCategory;
import gov.va.med.esr.UseCaseName;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.transaction.annotation.Transactional;

import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
/**
 * The Demographic Service Implementation.
 *
 * @author DNS   LEV
 * @author Andrew Pach
 * @version 3.0
 */
public class DemographicServiceImpl extends AbstractRuleAwareServiceImpl implements DemographicService
{

	private static final String INCOMETEST_UPD_LASTEDITEDDATE_QRY = "SSNVerificationResponseProcess.updateIncomeTestLastEditedDate";

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

    /**
     * An instance of eligibilityEnrollmentService
     */
    private EligibilityEnrollmentService eligibilityEnrollmentService = null;

    /**
     * HistoryDAO that retrieves the address history data.
     */
    private HistoryDAO addressHistoryDAO = null;
    /**
     * HistoryDAO that retrieves the insurance history data.
     */
    private HistoryDAO insuranceHistoryDAO = null;

    /**
     * HistoryDAO that retrieves the demographic history data.
     */
    private HistoryDAO demographicHistoryDAO = null;

    /**
     * GenericDAO for generic dao operations
     */
    private DAOOperations genericDAO;

    /**
     * SSNVerificationDetailDAO that retrieves SSNVerificationDetail data
     */
    private SSNVerificationDetailDAO ssnVerificationDetailDAO;

    /**
     * An instance of addressDAO
     */
    private AddressDAO addressDAO = null; 
    
	private TriggerRouter triggerRouter = null;
	
    private ConfidentialAddressCategoryDAO confidentialAddressCategoryDAO = null;
    
    private ConfidentialAddressCategoryTypeDAO confidentialAddressCategoryTypeDAO = null;

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

    /**
     * @see gov.va.med.esr.service.DemographicService#getAddressHistoryChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    public Set getAddressHistoryChangeTimes(EntityKey personID) throws ServiceException
    {
        try
        {
            return addressHistoryDAO.getHistoryChangeTimes(personID);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getAddressHistoryByChangeTime(ChangeEvent)
     */
    public HistoricalInfo getAddressHistoryByChangeTime(ChangeEvent event) throws ServiceException
    {
        try
        {
            return addressHistoryDAO.getHistoryByChangeTime(event);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getInsuranceHistoryChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    public Set getInsuranceHistoryChangeTimes(EntityKey personID) throws ServiceException
    {
        try
        {
            return insuranceHistoryDAO.getHistoryChangeTimes(personID);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getInsuranceHistoryByChangeTime(ChangeEvent)
     */
    public HistoricalInfo getInsuranceHistoryByChangeTime(ChangeEvent event) throws ServiceException
    {
        try
        {
            return insuranceHistoryDAO.getHistoryByChangeTime(event);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }
    /**
     * @see gov.va.med.esr.service.DemographicService#getDemographicHistoryChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    public Set getDemographicHistoryChangeTimes(EntityKey personID) throws ServiceException
    {
        try
        {
            return demographicHistoryDAO.getHistoryChangeTimes(personID);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getDemographicHistoryByChangeTime(ChangeEvent)
     */
    public HistoricalInfo getDemographicHistoryByChangeTime(ChangeEvent event) throws ServiceException
    {
        try
        {
            // Get the main Person history objects
            return demographicHistoryDAO.getHistoryByChangeTime(event);
        }
        catch (DAOException e)
        {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    public Set getIdentityTraitsChangeTimes(EntityKey vpidKey) throws ServiceException {
    	return doGetIdentityTraitsChangeTimes(vpidKey, false);
    }
    /**
     * @see gov.va.med.esr.service.DemographicService#getIdentityTraitsChangeTimes(gov.va.med.fw.model.EntityKey)
     */
    private Set doGetIdentityTraitsChangeTimes(EntityKey vpidKey, boolean onlyGetTraitsThatESRSubmitted) throws ServiceException
    {
        // Get the list of traits for this VPID
        List traitList = getTraitHistory(CommonEntityKeyFactory.createVPIDEntityKey(vpidKey.getKeyValueAsString()), onlyGetTraitsThatESRSubmitted);

        // Create a set of change events
        Set changeEventSet = new HashSet();
        for (Iterator iterator = traitList.iterator(); iterator.hasNext();)
        {
            PersonIdentityTraits traits = (PersonIdentityTraits)iterator.next();
            changeEventSet.add(new ChangeEvent(traits.getAuditInfo().getChangeDate(), traits.getVpid()));
        }

        return changeEventSet;
    }

    public HistoricalInfo getIdentityTraitsHistoryByChangeTime(ChangeEvent event) throws ServiceException {
    	return doGetIdentityTraitsHistoryByChangeTime(event, false);
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getIdentityTraitsHistoryByChangeTime(ChangeEvent)
     */
    private HistoricalInfo doGetIdentityTraitsHistoryByChangeTime(ChangeEvent event, boolean onlyGetTraitsThatESRSubmitted)
    	throws ServiceException
    {
        // Get the list of traits for the VPID associated with this entity key
        List traitList = getTraitHistory((VPIDEntityKey)event.getEntityKey(), onlyGetTraitsThatESRSubmitted);

        // Create the person records to return
        Person currentPerson = new Person();
        Person previousPerson = new Person();
        currentPerson.setPreviousVersion(previousPerson);

        // Variables to hold the current and previous traits
        PersonIdentityTraits currentTraits = null;
        PersonIdentityTraits previousTraits = null;

        // Iterate through the list of history traits and look for the current and previous traits.
        // We are iterating backwards to go from the newest to the oldest updates
        for (int i=traitList.size()-1; ((i >= 0) && (previousTraits == null)); i--)
        {
            PersonIdentityTraits traits = (PersonIdentityTraits)traitList.get(i);

            // The current traits are set when they haven't been set yet and the timestamps match
            if ((currentTraits == null) && (traits.getAuditInfo().getChangeDate().equals(event.getTimeStamp())))
            {
                currentTraits = traits;
            }
            else
            {
                // The previous traits are set on the record right after the current traits have been set
                // (i.e. when the previous traits haven't been set yet and the current traits have already been set).
                if ((previousTraits == null) && (currentTraits != null))
                {
                    previousTraits = traits;
                }
            }
        }

        // Overlay all the data onto the current and previous person
        if (currentTraits != null)
        {
            currentPerson.setIdentityTraits(currentTraits);
            currentPerson.setModifiedOn(currentTraits.getAuditInfo().getChangeDate());
            currentPerson.setModifiedBy(new ESRUserPrincipalImpl(currentTraits.getAuditInfo().getChangeUser()));
        }
        if (previousTraits != null)
        {
            previousPerson.setIdentityTraits(previousTraits);
            previousPerson.setModifiedOn(previousTraits.getAuditInfo().getChangeDate());
            previousPerson.setModifiedBy(new ESRUserPrincipalImpl(previousTraits.getAuditInfo().getChangeUser()));
        }

        // Return the history based on the current and previous person objects with the trait information
        // set on both.
        return new HistoricalInfo(event, currentPerson);
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#updateRequestSSNVerificationData(gov.va.med.esr.common.model.person.SSNVerification,
     *String,Object[])
     */
    public SSNVerification updateRequestSSNVerificationData(SSNVerification ssnVerification,
                                                            List newSSNVerificationDetails,
                                                            String updatedQueryString,
                                                            Object[] spouseDependentsSSNIds) throws ServiceException
    {
        try
        {
            // Persist spouse and dependent ssns
            if (updatedQueryString != null)
            {
                getGenericDAO().bulkUpdate(updatedQueryString, spouseDependentsSSNIds);
            }

            // Persist the SSN Verification and SN VErification Details, removed the
            // cacade option for the children on this object so need to persist childeren
            // manually here.
            getGenericDAO().saveObject(ssnVerification);

            for ( int i=0; newSSNVerificationDetails != null && i<newSSNVerificationDetails.size();i++)
            {
                getGenericDAO().saveObject(newSSNVerificationDetails.get(i));
            }

        }
        catch (DAOException e)
        {
            throw new ServiceException("Error updating Request SSN Verification data " , e);
        }

        return ssnVerification;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#updateDemographicInformation(gov.va.med.esr.common.model.person.Person)
     */
    public Person updateDemographicInformation(Person incoming) throws ServiceException
    {
        Validate.notNull(incoming, "A veteran must not be null");

        Person result = this.getPersonService().getPerson(
            (PersonEntityKey)incoming.getEntityKey(), incoming.getIdentityTraits());
        Validate.notNull(result, "A veteran on file must not be null.");

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

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(result);
        //CCR12710
        if (logger.isDebugEnabled()) {
	          logger.debug("DemographicRuleSvcImpl updateDemoInfo before change : incoming: " + incoming);
	    }

        // Step 1: Update a veteran on file with demographic information.
        this.getDemographicRuleService().manageDemographicInfo(incoming, result);

        // Step 2: Call the enrollment service to determine eligibility.
        this.getEligibilityEnrollmentService().assessEEImpact(result, false);

        // Step 3: Send update Z11
        this.getEventRuleService().manageMessageEvents(result);
        this.getEventRuleService().manageHandBookEvents(result);

        // CCR 12062
        this.addPersonChangeEventsForAdvice(result);

        //CCR12710
        if (logger.isDebugEnabled()) {
	          logger.debug("DemographicRuleSvcImpl updateDemoInfo at save : incoming: " + result);
	    }


        // Step 4: Save the updated person
        result = this.getPersonService().save(result);

        return result;
    }

    private void addPersonChangeEventsForAdvice(Person result) throws ServiceException {
    	/**
    	 * CCR 12062
    	 * 1. Claim Folder Location
    	 * 2. Claim Folder Number
    	 */
    	this.getEventRuleService().addPersonChangeEventsForAdvice(result);
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#processDemographicInformation(gov.va.med.esr.common.model.lookup.VAFacility,
     *gov.va.med.esr.common.model.person.Person)
     */
    public Person processDemographicInformation(VAFacility sendingFacility, Person incoming) throws ServiceException
    {
        Validate.notNull(incoming, "A veteran must not be null");

        // This call should always return a person since a person must have
        // already been querried through a search to by the messaging.
        Person result = this.getPersonService().getPerson((PersonEntityKey)incoming.getEntityKey());

        // Step 1: Update a veteran on file with demographic information then
        // Send Update Message (Z11).
        // (Should Z11 message be sent after the database update is successful?)
        this.getDemographicRuleService().processDemographicInfo(sendingFacility, incoming, result,false,"N");

        // Persist person
        this.getPersonService().save(result);

        return result;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#processSSNVerificationResponse(gov.va.med.esr.common.batchprocess.SSASSNVerificationData)
     */
    public Person updateSSNVerificationResponse(SSASSNVerificationData incoming) throws ServiceException
    {
        SSASSNVerificationData resultSSNVerificationData = new SSASSNVerificationData();

        SSNVerificationDetail ssnVerificationDetail = getSSNVerificationDetail(incoming);

        Person person = null;

        SSN ssn = null;

        Relation relation=null;

        if (ssnVerificationDetail != null)
        {
            incoming.setHECInternalIdMatched(true);
            incoming.setSsnVerificationForSpouseOrDependent(!(ssnVerificationDetail.getSsnId() == null));

            // If verification for spouse or dependent
            if (incoming.isSsnVerificationForSpouseOrDependent()) {
				incoming.setSsnId(String.valueOf(ssnVerificationDetail
						.getSsnId()));
				try {
					EntityKey entityKey = CommonEntityKeyFactory
							.createSSNEntityKey(String
									.valueOf(ssnVerificationDetail.getSsnId()));

					ssn = (SSN) getGenericDAO().getByKey(entityKey);
				} catch (DAOException e) {
					throw new ServiceException("Could not get SSN for SSN ID "
							+ ssnVerificationDetail.getSsnId(), e);
				}

				//If SSN is null, that means it was deleted in ESR. Could happen if
				//a Pesudo SSN comes in a message and deletes the original SSN.
				//In that case, throw an exception which will mark the record as failed.
				if (ssn == null)
					throw new ServiceException("No SSN exists for SSN ID "
							+ ssnVerificationDetail.getSsnId());

				// Relation cannot be null
				relation = ssn.getRelation();

				if (Relationship.CODE_SPOUSE.getCode().equals(
						relation.getRelationship().getCode())) {
					incoming.setSsnVerificationForSpouse(true);
				} else {
					incoming.setSsnVerificationForDependent(true);
				}

				//person = relation.getPerson();
				person = getPersonService().getPerson(relation.getPerson().getPersonEntityKey());
			}
            else
            {
                // SSNVerificationDetail will have a person Id for veteran ssn
                // verification
                person = getPersonService()
                    .getPerson(CommonEntityKeyFactory.createPersonIdEntityKey(ssnVerificationDetail.getPersonId()));
            }
        }

        if (ssn == null)
			throw new ServiceException("No SSN exists for SSN ID "
					+ ((ssnVerificationDetail != null) ? ssnVerificationDetail.getSsnId() : null));

        this.getDemographicRuleService().processSSNVerificationResponse(incoming, person, resultSSNVerificationData, relation);

        // CodeCR7451 only triggerMessage when it is VOA Only
        if (person != null && person.isVOAOnly())
        {
     /* check if SSN is NOT for spouse or dependent AND SSN verification status is VERIFIED
      *  there is no method provided to check if the SSN is for Veteran
      * */
             SSAVerificationStatus ssaVerificationStatus = resultSSNVerificationData.getSsaVerificationStatus();

             if (!(incoming.isSsnVerificationForSpouseOrDependent()) &&
               (ssaVerificationStatus !=null && SSAVerificationStatus.VERIFIED.getCode().equals(ssaVerificationStatus.getCode()) ) )
             {
      /* invoke TriggerMessage rule flow by calling processMessageEvents() */
              this.getEventRuleService().processMessageEvents(person);
             }
        }
        // end of CCR7451

        if (person != null && incoming.isHECInternalIdMatched())
        {
        	IncomeTest incomeTest = person.getIncomeTest(person.getLatestIncomeYear());
        	Date editedDate = Calendar.getInstance().getTime();

        	if (incoming.isSsnVerificationForSpouseOrDependent())
            {
            	try
                {
                    ssn.setSsaMessage(resultSSNVerificationData.getSsaMessage());
                    ssn.setSsaVerificationStatus(resultSSNVerificationData.getSsaVerificationStatus());

                    ssn.setSsaVerificationDate(editedDate);
                    ssn.setSsaReceivedDate(editedDate); //CCR 11930 - it doesn't matter for spouse/dependent, but won't hurt by just setting it

                    getGenericDAO().saveObject(ssn);
                    //DNS   doank CCR9064: prevent null exception when there's no income test
                    if(incomeTest != null)
                    {
                    	updateIncomeTestLastEditedDate(incomeTest,editedDate );
                    }
                    logger.info("Updated Spouse/Dependent SSN for ID " + ssn.getEntityKey().getKeyValueAsString());

                }
                catch (DAOException e)
                {
                    throw new ServiceException("Could not save SSN", e);
                }
            }
            else
            {
                PersonIdentityTraits traits = this.getPsDelegateService().extractIdentityTraits(person);
                SSN veteranSsn = traits.getSsn();
                veteranSsn.setSsaMessage(resultSSNVerificationData.getSsaMessage());
                veteranSsn.setSsaVerificationStatus(resultSSNVerificationData.getSsaVerificationStatus());
                veteranSsn.setSsaVerificationDate(editedDate);
                //CCR 11930 - in case of "Invalid per SSA", the "effectiveTime" will be set in the request to MVI
                //Please see CCR 11777 changes in IdMWebServiceImpl.java
                veteranSsn.setSsaReceivedDate(editedDate);


                //DNS   doank CCR9064: prevent null exception when there's no income test
                if(incomeTest != null )
                {
                	updateIncomeTestLastEditedDate(incomeTest,editedDate );
                }

				//CCR 11666: Update MVI to update SSN status and sent time for ESR correlation
				this.getPersonService().updateProfileForESRCorrelation(person);
            }
        }

        return person;
    }



    public void updateIncomeTestLastEditedDate(IncomeTest incomeTest, Date lastEditedDate) throws ServiceException
    {

    	if ( incomeTest == null || incomeTest.getStatuses() == null  ) return;
    	Set statuses = incomeTest.getStatuses();
    	try{

    		for (Iterator i= statuses.iterator(); i.hasNext();)	{
    			IncomeTestStatus status  = (IncomeTestStatus)i.next();
    			Map contextData = new HashMap();
    			contextData.put("lastEditedDate", lastEditedDate);
    			contextData.put("itdetailid", new BigDecimal(status.getEntityKey().getKeyValueAsString()));
    			AbstractDAOAction callback = new AbstractDAOAction(contextData) {
					public Object execute(Session session) {
						Query query = session.getNamedQuery(INCOMETEST_UPD_LASTEDITEDDATE_QRY);
						query.setParameter("lastEditedDate", (Date)getContextData().get("lastEditedDate"));
						query.setParameter("itdetailid", (BigDecimal)getContextData().get("itdetailid"));
		                return new Integer(query.executeUpdate());
		            }
    			};

    			Integer updateCount = (Integer) getGenericDAO().execute(callback);
    			if (updateCount.intValue() < 1) {
    				if(logger.isWarnEnabled()) {
    					logger.warn("Income Test Lasted Updated did not update =" + status.getEntityKey().getKeyValueAsString());
    				}
	    		}
    		}
    	}
    	catch(Exception e)
    	{
    		logger.error("Exception Income Test Lasted Updated Date", e);
    		throw new ServiceException(e);
    	}
    }



    /**
     * @see gov.va.med.esr.service.DemographicService#updateContactInformation(gov.va.med.esr.common.model.person.Person)
     */
    public Person updateContactInformation(Person incoming) throws ServiceException
    {
        Validate.notNull(incoming, "A veteran must not be null");

        // Get the onFile person
        Person result = this.getPersonService().getPerson((PersonEntityKey)incoming.getEntityKey());

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

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(result);

        // If any part of the permanent address updatable fields changed, update the change date
        // with the transaction timestamp
        //if (!AbstractEntity.matchesDomainValues(incoming.getPermanentAddress(), result.getPermanentAddress()))
        //CCR11578
        
        // Correction, not only the permanent address, but all four addresses. Watch out for more addresses as they are added.
        // CR 13726
        handleAddressChange(incoming.getPermanentAddress(), result.getPermanentAddress());
        handleAddressChange(incoming.getResidentialAddress(), result.getResidentialAddress());
        handleAddressChange(incoming.getTemporaryCorrespondenceAddress(), result.getTemporaryCorrespondenceAddress());
        handleAddressChange(incoming.getConfidentialAddress(), result.getConfidentialAddress());
        if(incoming.getConfidentialAddress() !=null){
        	if(incoming.getConfidentialAddressCategories()!=null){
           		List categoryList = getConfAddrCategories(incoming);
           		result.removeAllConfidentialAddressCategories();//removing existing category types of the person on file
           		
           		//Setting up new category types for person from received form.
           		ConfidentialAddressCategoryType cact;
           		for (int i=0; i<categoryList.size(); i++){
           			cact = (ConfidentialAddressCategoryType) categoryList.get(i);
           			result.addConfidentialAddressCategory(cact);
           		}	
        	}

        }
        // Execute rules
        ContactInfoRuleService contactInfoRuleService = this.getContactInfoRuleService();
        contactInfoRuleService.manageAddresses(incoming.getAddresses(), result);
        contactInfoRuleService.manageElectronicAddresses(incoming.getEmails(), result);
        contactInfoRuleService.managePhones(incoming.getPhones(), result);

        //call handbook rule 3.5 Keeping the handbook rules separate from other rules as
        // It is not running in production as part of 3.5 release.
        contactInfoRuleService.manageHandBookForBadAddressText(incoming.getAddresses(), result);
        // Persist person
        result = this.getPersonService().save(result);

        return result;
    }

    /**
	 * DO NOT USE for generic save demographics cases
	 * This is utility for creating address_h entry during correspondence generation to track
	 * address at time of mail request
     * @param Address - unmodified address from getLetterAddress
     *
     */
    public void saveAddress(Address onFileAddress) throws ServiceException {
    	try
        {
            getGenericDAO().saveObject(onFileAddress);
            getGenericDAO().flush();

        }
        catch (Exception e)
        {
        	throw new ServiceException("Error saving Address " , e);
        }
    }

    //CCR 11403: relocate here the logic in PersonServiceImpl.save(incomingPerson, overrideLocking)
    //after the incomingPerson is saved
    private void resetSSNVerificationStatus(Person incoming, Person onFile) throws ServiceException
    {
		if (incoming.getPersonEntityKey() != null) //not a new person
        {
			PersonIdentityTraits onFileTraits = onFile.getIdentityTraits();
			PersonIdentityTraits incomingTraits = incoming.getIdentityTraits();
			// See if identityTraits changed
			if (!incomingTraits.equals(onFileTraits))
            {
				/* SSAVerificationStatus will be reset under the following conditions:
				 * 		a) the SSN text changed
				 * 		b) any part of the Name AND DOB are changed AND current status is VERIFIED
				 * 		c) (any part of the Name OR DOB are changed) AND current status is INVALID
				 */
				boolean shouldResetSSAVerificationStatus = false;

				SSN incomingSSN = incomingTraits.getSsn();
				SSN onFileSSN = onFileTraits.getSsn();
				String incomingSSNText =  incomingSSN != null ? incomingSSN.getSsnText() : StringUtils.EMPTY;
				String onFileSSNText = onFileSSN != null ? onFileSSN.getSsnText() : StringUtils.EMPTY;
				String onFileSSAVerificationStatusCode = onFileSSN != null && onFileSSN.getSsaVerificationStatus() != null ?
						onFileSSN.getSsaVerificationStatus().getCode() : StringUtils.EMPTY;
				// CCR 12323
				boolean traitsChanged = false;
				String incomingSSAVerificationStatusCode = incomingSSN != null && incomingSSN.getSsaVerificationStatus() != null ?
						incomingSSN.getSsaVerificationStatus().getCode() : StringUtils.EMPTY;

				// a)
				if (!onFileSSNText.equals(incomingSSNText) && !StringUtils.isEmpty(incomingSSNText)) {
					shouldResetSSAVerificationStatus = true;
					traitsChanged = true;
				// b)
				} else if(ObjectUtils.didObjectChange(onFileTraits.getLegalName(), incomingTraits.getLegalName()) &&
						ObjectUtils.didObjectChange(onFileTraits.getBirthRecord(), incomingTraits.getBirthRecord()) &&
								SSAVerificationStatus.VERIFIED.getCode().equals(onFileSSAVerificationStatusCode)) {
					shouldResetSSAVerificationStatus = true;
					traitsChanged = true;
				// c)
				} else if((ObjectUtils.didObjectChange(onFileTraits.getLegalName(), incomingTraits.getLegalName()) ||
						ObjectUtils.didObjectChange(onFileTraits.getBirthRecord(), incomingTraits.getBirthRecord())) &&
								SSAVerificationStatus.INVALID_PER_SSA.getCode().equals(onFileSSAVerificationStatusCode)) {
					shouldResetSSAVerificationStatus = true;
					traitsChanged = true;
				}
				// CCR 12323
				if (ObjectUtils.didObjectChange(onFileTraits.getGender(), incomingTraits.getGender())) {
					traitsChanged = true;
				}

				if(shouldResetSSAVerificationStatus) {
					incomingSSN.setSsaVerificationStatus(
                        getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.NEW_RECORD.getName()));
					incomingSSN.setSsaVerificationDate(null);
					incomingSSN.setSsaMessage(null);
                    //CCR 11666: insert into SSA verification queue
			    	this.getHelperService().addToSSNVerificationQueue(onFile);
				}

				this.getPersonService().updateProfileForESRCorrelation(incoming);
				// CCR 12323 tell post advice that traits changed. Although rules still have to execute,
				// all processing is unconditional so it's OK to set early.
				if (traitsChanged ||
						ObjectUtils.didObjectChange(onFileSSAVerificationStatusCode, incomingSSAVerificationStatusCode)) {
					onFile.setChangeEvent(UseCaseName.IDENTITY_TRAITS, UseCaseName.IDENTITY_TRAITS);
				}
			}
		}
    }
    /**
     * @see gov.va.med.esr.service.DemographicService#updateIdentityTraits(gov.va.med.esr.common.model.person.Person)
     */
    public Person updateIdentityTraits(Person incoming) throws ServiceException {
    	//11758 uses the composite call to get result person
        Person result = this.getPersonService().getPersonWithCompositeCall(incoming.getIdentityTraits().getVpid());

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

        resetSSNVerificationStatus(incoming, result);

        // Validate that an enrollment record exists for the on-file Person
        validateEnrollmentDetermination(result);

        // Apply rules and overlay the incoming identity traits onto the on-file version
        this.getDemographicRuleService().manageIdentityTraits(incoming, result);

        // Call the enrollment service to determine eligibility.
        this.getEligibilityEnrollmentService().assessEEImpact(result, false);
        //call hanbook rule
        this.getEventRuleService().manageHandBookEvents(result);

        //11758: if 200ESR correlation does not exist, add it
        if ("N".equals(result.getIdentityTraits().has200ESRCorrelation()))
        		this.getPersonService().addESRCorrelation(result);

        // Persist person and return it
        return this.getPersonService().save(result);
    }

    /**
     * @return Returns the eligibilityEnrollmentService.
     */
    public EligibilityEnrollmentService getEligibilityEnrollmentService()
    {
        return eligibilityEnrollmentService;
    }

    /**
     * @param eligibilityEnrollmentService The eligibilityEnrollmentService to set.
     */
    public void setEligibilityEnrollmentService(EligibilityEnrollmentService eligibilityEnrollmentService)
    {
        this.eligibilityEnrollmentService = eligibilityEnrollmentService;
    }

    public HistoryDAO getAddressHistoryDAO()
    {
        return addressHistoryDAO;
    }

    public void setAddressHistoryDAO(HistoryDAO addressHistoryDAO)
    {
        this.addressHistoryDAO = addressHistoryDAO;
    }

    public HistoryDAO getDemographicHistoryDAO()
    {
        return demographicHistoryDAO;
    }

    public void setDemographicHistoryDAO(HistoryDAO demographicHistoryDAO)
    {
        this.demographicHistoryDAO = demographicHistoryDAO;
    }

    /**
     * @return Returns the genericDAO.
     */
    public DAOOperations getGenericDAO()
    {
        return genericDAO;
    }

    /**
     * @param genericDAO The genericDAO to set.
     */
    public void setGenericDAO(DAOOperations genericDAO)
    {
        this.genericDAO = genericDAO;
    }

    /**
     * @return Returns the ssnVerificationDetailDAO.
     */
    public SSNVerificationDetailDAO getSsnVerificationDetailDAO()
    {
        return ssnVerificationDetailDAO;
    }

    /**
     * @param ssnVerificationDetailDAO The ssnVerificationDetailDAO to set.
     */
    public void setSsnVerificationDetailDAO(SSNVerificationDetailDAO ssnVerificationDetailDAO)
    {
        this.ssnVerificationDetailDAO = ssnVerificationDetailDAO;
    }

    /**
     * Returns an instance of addressDAO
     *
     * @return AddressDAO addressDAO.
     */
    public AddressDAO getAddressDAO()
    {
        return addressDAO;
    }

    /**
     * Sets the addressDAO of type AddressDAO
     *
     * @param addressDAO The addressDAO  to set.
     */
    public void setAddressDAO(AddressDAO addressDAO)
    {
        this.addressDAO = addressDAO;
    }


    /**
     * Returns an instance of confidentialAddressCategoryDAO
     *
     * @return ConfidentialAddressCategoryDAO confidentialAddressCategoryDAO.
     */
    public ConfidentialAddressCategoryDAO getConfidentialAddressCategoryDAO()
    {
        return confidentialAddressCategoryDAO;
    }

    /**
     * Sets the confidentialAddressCategoryDAO of type ConfidentialAddressCategoryDAO
     *
     * @param confidentialAddressCategoryDAO The confidentialAddressCategoryDAO  to set.
     */
    public void setConfidentialAddressCategoryDAO(ConfidentialAddressCategoryDAO confidentialAddressCategoryDAO)
    {
        this.confidentialAddressCategoryDAO = confidentialAddressCategoryDAO;
    }


    /**
     * @see gov.va.med.esr.service.DemographicService#processExternalDemographicsChange(gov.va.med.esr.service.external.demographics.DemographicsChangeSummary)
     */
    public void processExternalDemographicsChange(DemographicsChangeSummary changeSummary) throws ServiceException
    {
        if (logger.isInfoEnabled())
        {
            logger.info("ESR received an external demographics change event: "
                + changeSummary);
        }

        // Convert external key into internal key
        VPIDEntityKey vpid = CommonEntityKeyFactory.createVPIDEntityKey(changeSummary.getVpid());
        Person person = this.getPersonService().getPersonWithCompositeCall(vpid); //CCR 11758

        this.getDemographicRuleService().processExternalDemographicChanges(changeSummary.getChangeEvents(), person);

        if (this.requiresEECalculation(changeSummary.getChangeEvents()))
        {
            this.getEligibilityEnrollmentService().assessEEImpact(person, false);
            EventRuleService eventRuleService = this.getEventRuleService();
            eventRuleService.manageMessageEvents(person);
            eventRuleService.managePersonEvents(person);
            eventRuleService.manageHandBookEvents(person);
        }

        //CCR 11403: check enrollment records, add 200ESRCorreltion if necessary
        if ("N".equalsIgnoreCase(person.getIdentityTraits().has200ESRCorrelation()))  //CCR 11758
        {
        	this.getPersonService().addESRCorrelation(person);
        }

        // Save the person
        this.getPersonService().save(person);
    }

    /**
     * @return Returns the triggerRouter.
     */
    public TriggerRouter getTriggerRouter()
    {
        return triggerRouter;
    }

    /**
     * @param triggerRouter The triggerRouter to set.
     */
    public void setTriggerRouter(TriggerRouter triggerRouter)
    {
        this.triggerRouter = triggerRouter;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getPersonAddresses(gov.va.med.esr.common.model.person.id.PersonEntityKey)
     */
    public List getPersonAddresses(PersonEntityKey key) throws ServiceException
    {
        if (key == null)
        {
            return null;
        }

        List lst = null;
        try
        {
            AddressDAO addrDAO = this.getAddressDAO();
            lst = addrDAO.getPersonAddresses(new BigDecimal(key.getKeyValueAsString()));
        }
        catch (DAOException dex)
        {
            throw new ServiceException(dex.getMessage(), dex);
        }

        return lst;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getPersonAddresses(gov.va.med.esr.common.model.person.id.PersonEntityKey)
     */
    public List getConfAddrCategoriesByPersonId(PersonEntityKey key) throws ServiceException
    {
        if (key == null)
        {
            return null;
        }

        List lst = null;
        try
        {
            ConfidentialAddressCategoryDAO confidentialAddressCategoryDAO = this.getConfidentialAddressCategoryDAO();
            lst = confidentialAddressCategoryDAO.getConfAddCategoriesByPersonId(new BigDecimal(key.getKeyValueAsString()));
        }
        catch (DAOException dex)
        {
            throw new ServiceException(dex.getMessage(), dex);
        }

        return lst;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getLetterAddress(gov.va.med.esr.common.model.person.Person)
     */
    public Address getLetterAddress(Person person) throws ServiceException
    {
        if (person == null || person.getAddresses() == null || person.getAddresses().size() == 0)
        {
            return null;
        }

        return MailingAddressHelper.selectAddressForMailing(person.getAddresses());
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getUpdatedLetterAddress(gov.va.med.esr.common.model.comms.CommsLogEntry)
     */
    public Address getUpdatedLetterAddress(CommsLogEntry log) throws ServiceException
    {
        if (log == null || log.getPersonId() == null)
        {
            return null;
        }

        List addrLst =
            this.getPersonAddresses(CommonEntityKeyFactory.createPersonIdEntityKey(log.getPersonId().toString()));

        List confidentialAddressCategoryList = this.getConfAddrCategoriesByPersonId(CommonEntityKeyFactory.createPersonIdEntityKey(log.getPersonId().toString()));

        //Address latestAddr = MailingAddressHelper.selectAddressForMailing(addrLst);
        Address latestAddr = MailingAddressHelper.selectAddressForMailing(confidentialAddressCategoryList, addrLst);

        if (latestAddr == null || isLetterAddressSame(latestAddr, log))
        {
            return null;
        }

        return latestAddr;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getUpdatedHandbookAddress(gov.va.med.esr.common.model.comms.HandBookMailQueue)
     */
    public Address getUpdatedLetterAddress(HandBookMailQueue mailQueue) throws ServiceException
    {
        if (mailQueue == null || mailQueue.getPersonId() == null)
        {
            return null;
        }

        List addrLst =
            this.getPersonAddresses(CommonEntityKeyFactory.createPersonIdEntityKey(mailQueue.getPersonId().toString()));

        List confidentialAddressCategoryList = this.getConfAddrCategoriesByPersonId(CommonEntityKeyFactory.createPersonIdEntityKey(mailQueue.getPersonId().toString()));

        Address latestAddr = MailingAddressHelper.selectAddressForMailing(confidentialAddressCategoryList, addrLst);

        if (latestAddr == null || isLetterAddressSame(latestAddr, mailQueue))
        {
            return null;
        }

        return latestAddr;
    }

    /**
     * @see gov.va.med.esr.service.DemographicService#getUndeliverableMailUpdatedLetterAddress(gov.va.med.esr.common.model.comms.CommsLogEntry)
     */
    public Address getUndeliverableMailUpdatedLetterAddress(CommsLogEntry log) throws ServiceException
    {
        // Make sure we have a CommsLogEntry and a Person Id
        if (log == null || log.getPersonId() == null)
        {
            return null;
        }

        // Get the current address list for the person
        List addressList = this.getPersonAddresses(
            CommonEntityKeyFactory.createPersonIdEntityKey(log.getPersonId().toString()));

        List confidentialAddressCategoryList = this.getConfAddrCategoriesByPersonId(CommonEntityKeyFactory.createPersonIdEntityKey(log.getPersonId().toString()));

        // Determine which address would be used now to send letters.  This address might be the
        // undeliverable one since we didn't mark a letter as undeliverable yet.
        //Address addressToUseNow = MailingAddressHelper.selectAddressForMailing(addressList);
        Address addressToUseNow = MailingAddressHelper.selectAddressForMailing(confidentialAddressCategoryList, addressList);

        // Get the address that was used to send out the letter.
        Address letterAddress = log.getAddress();

        // If the address to use and the address that was used to send out the letter are different, then
        // we have a new address to use right now so return it.
        if (!(ObjectUtils.equals(addressToUseNow, letterAddress)))
        {
            return addressToUseNow;
        }

        // The address used is the same as the one we would now use so we need consider any on-file
        // address that matches the one sent as invalid.  As such, create a new list of addresses
        // that don't contain the address used.
        List newAddressList = new ArrayList();
        for (Iterator iterator = addressList.iterator(); iterator.hasNext();)
        {
            Address newAddress = (Address)iterator.next();
            if (!newAddress.equals(letterAddress))
            {
                newAddressList.add(newAddress);
            }
        }

        // Return the address we would use now since we removed the invalid ones from the list
        return MailingAddressHelper.selectAddressForMailing(newAddressList);
    }

    /**
     * Gets a list of the history traits for the passed in VPID entity key.
     *
     * @param vpidEntityKey The VPID entity key.
     * @param onlyGetTraitsThatESRSubmitted If this is true, then the only traits returned will be those that ESR
     * submitted for change
     *
     * @return The list of PersonIdentityTraits.
     * @throws ServiceException if any problems were encountered.
     */
    protected List getTraitHistory(VPIDEntityKey vpidEntityKey, boolean onlyGetTraitsThatESRSubmitted) throws ServiceException
    {
        // Get the list of traits for this VPID
    	if(!onlyGetTraitsThatESRSubmitted)
    		return getPsDelegateService().getIdentityTraitsUpdateHistory(vpidEntityKey);

    	// only gets those that ESR submitted
    	return getPsDelegateService().getSubmittedIdentityTraitsUpdateHistory(vpidEntityKey);
    }

    /**
     * Determines if the latest address and the one on the comms log entry are the same
     *
     * @param latestAddr the latest address
     * @param log the comms log entry
     *
     * @return True if the addresses are the same or false if not.
     */
    private boolean isLetterAddressSame(Address latestAddr, CommsLogEntry log)
    {
        return ObjectUtils.equals(latestAddr, log.getAddress());
    }

    /**
     * Overloaded method to handle handbook
     */
    private boolean isLetterAddressSame(Address latestAddr, HandBookMailQueue mailQueue) throws ServiceException
    {
  		return ObjectUtils.equals(latestAddr, mailQueue.getAddress());
    }

    /**
     * Determines if an EE calculation is required
     *
     * @param changes the set of changes
     *
     * @return True if required or false if not.
     */
    private boolean requiresEECalculation(Set changes)
    {
        if (changes == null)
        {
            return false;
        }

        for (Iterator i = changes.iterator(); i.hasNext();)
        {
            DemographicsChangeEvent demographicsChangeEvent = (DemographicsChangeEvent)i.next();
            if (demographicsChangeEvent.getChangeType().equals(DemographicsChangeType.DATE_OF_DEATH_CHANGE))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Retrieve a SSNVerificationDetail if it does not exist
     *
     * @param ssnVerificationData the SSN verification data
     *
     * @return the SSN Verification Detail
     * @throws ServiceException if any problems were encountered
     */
    private SSNVerificationDetail getSSNVerificationDetail(SSASSNVerificationData ssnVerificationData)
        throws ServiceException
    {
        SSNVerificationDetail verificationDetail = null;
        try
        {
            // SSNVerificationDetailDAO dao
            verificationDetail = getSsnVerificationDetailDAO()
                .getSSNVerificationDetailByHECInternalId(ssnVerificationData.getHECInternalID());

        }
        catch (DAOException e)
        {
            throw new ServiceException("Could not get SSNVerification Detail "
                + "by HEC Internal Id: " + ssnVerificationData.getHECInternalID(), e);
        }

        return verificationDetail;
    }

	/* (non-Javadoc)
	 * @see gov.va.med.esr.service.DemographicService#getSubmittedIdentityTraitsChangeTimes(gov.va.med.fw.model.EntityKey)
	 */
	public Set getSubmittedIdentityTraitsChangeTimes(EntityKey personID) throws ServiceException {
		return doGetIdentityTraitsChangeTimes(personID, true);
	}

	/* (non-Javadoc)
	 * @see gov.va.med.esr.service.DemographicService#getSubmittedIdentityTraitsHistoryByChangeTime(gov.va.med.esr.service.impl.ChangeEvent)
	 */
	public HistoricalInfo getSubmittedIdentityTraitsHistoryByChangeTime(ChangeEvent event) throws ServiceException {
		return doGetIdentityTraitsHistoryByChangeTime(event, true);
	}

    public HistoryDAO getInsuranceHistoryDAO() {
        return insuranceHistoryDAO;
    }

    public void setInsuranceHistoryDAO(HistoryDAO insuranceHistoryDAO) {
        this.insuranceHistoryDAO = insuranceHistoryDAO;
    }

    /**
     * Process a new DeathRecord for a Person.  This is called by the DateOfDeath
     * batch process.
     *
     * @param Person The person with a new DeathRecord
     */
    public Person processDeathRecordFromIdm(Person incoming) throws ServiceException {
    	Validate.notNull(incoming, "A veteran must not be null");

    	Person result = this.getPersonService().getPerson(	(PersonEntityKey)incoming.getEntityKey());
    	Validate.notNull(result, "A veteran on file must not be null.");

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

    	// Validate that an enrollment record exists for the on-file Person
    	validateEnrollmentDetermination(result);

    	// Determine if a PSD demographic update has occurred
    	//boolean psdDemographicUpdate = determinePsdDemographicUpdate(incoming, result);

    	VAFacility sendingFacility = incoming.getDeathRecord() != null ? incoming.getDeathRecord().getFacilityReceived() : null;

    	this.getDemographicRuleService().processDemographicInfo(sendingFacility, incoming, result, false,true);

    	// Call the enrollment service to determine eligibility.
    	this.getEligibilityEnrollmentService().assessEEImpact(result, false);
        this.getEventRuleService().manageMessageEvents(result);

    	// Save the updated person
    	result = this.getPersonService().save(result);

		return result;
    }

	public Person processDateOfDeathFromIdm(Person onFile, Date dateOfDeath) throws ServiceException {
		Validate.notNull(dateOfDeath, "The Date of Death must not be null");
		Validate.notNull(onFile, "An onFile person must not be null");

		Person incoming = (Person)onFile.clone();

	   	// Validate that an enrollment record exists for the on-file Person
    	validateEnrollmentDetermination(onFile);
    	DemographicRuleService service = this.getDemographicRuleService();
    	service.attachDeathRecordFromIdm(incoming, dateOfDeath);
    	VAFacility sendingFacility = incoming.getDeathRecord() != null ? incoming.getDeathRecord().getFacilityReceived() : null;
    	service.processDemographicInfo(sendingFacility, incoming, onFile, false, true);

    	// Call the enrollment service to determine eligibility.
    	this.getEligibilityEnrollmentService().assessEEImpact(onFile, false);
        this.getEventRuleService().manageMessageEvents(onFile);

    	// Save the updated person
    	return this.getPersonService().save(onFile);
	}

	//CCR11578 If only change source and change site are changed, the change effectve date will not be updated
	private void handleAddressChange(Address incoming, Address result) {
		boolean changeAddressDate = false;

		if (result != null) {
			Address cloneAddr = (Address)result.clone();
			cloneAddr.setChangeSource(incoming.getChangeSource());
			cloneAddr.setChangeSite(incoming.getChangeSite());
			changeAddressDate = !AbstractEntity.matchesDomainValues(incoming, cloneAddr);
			
			//{RR} - 294726 start and endDate for temporary and cofidential addresses
			if(incoming.getType().getCode().equalsIgnoreCase("C") || incoming.getType().getCode().equalsIgnoreCase("CNF")){
				result.setStartDate(incoming.getStartDate());
				result.setEndDate(incoming.getEndDate());
			}
		} else {
			//CCR11886 - NPR during update on Veteran record containing no address
			//if there is no address on file then always return as address data changed
			if (incoming == null) {
			 changeAddressDate = false;
			} else {
			 changeAddressDate = true;
			}
		}

		if (changeAddressDate) {
	    	incoming.setChangeDate(new Date(getTimestampManager().getTransactionTimestamp().getTime()));			
		}
	}

	public void sendDodUpdate(TriggerEvent triggerEvent) throws ServiceException {
		ProcessTriggerEvent event = (ProcessTriggerEvent)triggerEvent;
		try {
			Person person = null;
			PersonEntityKey key = event.getPersonId();
			if (key != null)
				person = getPersonService().getPerson(key);
				getPersonService().updateProfileForESRCorrelation(person);
		}
		catch (ServiceException e) {
			throw new ServiceException(
					"Error retrieving a person from the ProcessTriggerEvent", e);
		}

	}

	
    public ConfidentialAddressCategoryTypeDAO getConfidentialAddressCategoryTypeDAO() {
		return confidentialAddressCategoryTypeDAO;
	}

	public void setConfidentialAddressCategoryTypeDAO(
			ConfidentialAddressCategoryTypeDAO confidentialAddressCategoryTypeDAO) {
		this.confidentialAddressCategoryTypeDAO = confidentialAddressCategoryTypeDAO;
	}
	
	/**
	 * This method will Invokae the DAO method to get a specific object from of  
	 * ConfidentialAddressCategoryType with the provided code. 
	 * @param String (code)
	 * -------------------------------------------------------------------------
	 */
	public ConfidentialAddressCategoryType getConfidentialAddressCategoryTypesByCode(String code) {
		
		ConfidentialAddressCategoryType catType = null;

		try {
			catType = this.getConfidentialAddressCategoryTypeDAO().getConfidentialAddressCategoryTypeByCode(code);
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return catType;
	}
	
	
    /**
     * Get the list of ConfidentialAddressCategoryType's
     * @param person
     * @return
     */
    public List getConfAddrCategories(Person person) {
        // Create a list for Confidential Address Categories
        Set categoriesSource = person.getConfidentialAddressCategories();
        List categoriesTarget = new ArrayList();
        
        if (categoriesSource != null && categoriesSource.size() > 0) {            
            Object catArray[] = categoriesSource.toArray();

            for (int i=0; i < catArray.length; i++) {
                categoriesTarget.add(((ConfidentialAddressCategory)catArray[i]).getType());
            }
        }
        return categoriesTarget;
    }
    

}
