/*****************************************************************************************
 * Copyright � 2004 VHA. All rights reserved
 ****************************************************************************************/
package gov.va.med.esr.common.model.person;

// Java classes
import gov.va.med.esr.common.infra.PredicatedTransformer;
import gov.va.med.esr.common.infra.RemoveTransformedSet;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.SiteYear;
import gov.va.med.esr.common.model.comms.DeliveryPreference;
import gov.va.med.esr.common.model.ee.AgentOrangeExposure;
import gov.va.med.esr.common.model.ee.Application;
import gov.va.med.esr.common.model.ee.CampLejeuneVerification;
import gov.va.med.esr.common.model.ee.CancelDecline;
import gov.va.med.esr.common.model.ee.CatastrophicDisability;
import gov.va.med.esr.common.model.ee.ClinicalDetermination;
import gov.va.med.esr.common.model.ee.Decoration;
import gov.va.med.esr.common.model.ee.EligibilityVerification;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.ee.EnrollmentOverride;
import gov.va.med.esr.common.model.ee.EnvironmentalContaminationExposure;
import gov.va.med.esr.common.model.ee.FeeBasis;
import gov.va.med.esr.common.model.ee.HealthBenefitProfile;
import gov.va.med.esr.common.model.ee.IncompetenceRuling;
import gov.va.med.esr.common.model.ee.IneligibilityFactor;
import gov.va.med.esr.common.model.ee.MedalOfHonor;
import gov.va.med.esr.common.model.ee.MedicaidFactor;
import gov.va.med.esr.common.model.ee.MilitaryService;
import gov.va.med.esr.common.model.ee.MilitaryServiceEpisode;
import gov.va.med.esr.common.model.ee.MilitaryServiceSiteRecord;
import gov.va.med.esr.common.model.ee.MilitarySexualTrauma;
import gov.va.med.esr.common.model.ee.MonetaryBenefitAward;
import gov.va.med.esr.common.model.ee.NoseThroatRadium;
import gov.va.med.esr.common.model.ee.PrisonerOfWar;
import gov.va.med.esr.common.model.ee.PurpleHeart;
import gov.va.med.esr.common.model.ee.RadiationExposure;
import gov.va.med.esr.common.model.ee.ReceivedEligibility;
import gov.va.med.esr.common.model.ee.VcEligibility;
import gov.va.med.esr.common.model.ee.ReceivedEnrollment;
import gov.va.med.esr.common.model.ee.SHAD;
import gov.va.med.esr.common.model.ee.ServiceConnectionAward;
import gov.va.med.esr.common.model.ee.SpecialFactor;
import gov.va.med.esr.common.model.ee.SpinalCordInjury;
import gov.va.med.esr.common.model.financials.BeneficiaryTravel;
import gov.va.med.esr.common.model.financials.FinancialStatement;
import gov.va.med.esr.common.model.financials.InProcessFinancialInfo;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.financials.PatientVisitSummary;
import gov.va.med.esr.common.model.insurance.InsurancePolicy;
import gov.va.med.esr.common.model.insurance.Medicare;
import gov.va.med.esr.common.model.insurance.PrivateInsurance;
import gov.va.med.esr.common.model.lookup.AddressType;
import gov.va.med.esr.common.model.lookup.AssociationType;
import gov.va.med.esr.common.model.lookup.ConfidentialAddressCategoryType;
import gov.va.med.esr.common.model.lookup.Gender;
import gov.va.med.esr.common.model.lookup.MaritalStatus;
import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.lookup.PhoneType;
import gov.va.med.esr.common.model.lookup.RaceType;
import gov.va.med.esr.common.model.lookup.Relationship;
import gov.va.med.esr.common.model.lookup.Religion;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.lookup.SelfIdentifiedGenderIdentity;
import gov.va.med.esr.common.model.lookup.SensitivityChangeSource;
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.party.ConfidentialAddressCategory;
import gov.va.med.esr.common.model.party.Email;
import gov.va.med.esr.common.model.party.Phone;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.model.AuditInfo;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.util.CollectionUtils;
import gov.va.med.fw.util.Reflector;
import gov.va.med.ps.model.PersonVPID;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.AndPredicate;
import org.apache.commons.collections.functors.InstanceofPredicate;
import org.apache.commons.collections.functors.NotNullPredicate;
import org.apache.commons.collections.set.TransformedSet;
import org.apache.commons.collections.set.UnmodifiableSet;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * Person BOM
 *
 * @author Yi He
 * @author Ghazenfer Mansoor
 * @author Gregory Bohmer
 * @version 1.0
 */
public class Person extends AbstractKeyedEntity  {

   private static final long serialVersionUID = 6901518517513943128L;

   private Boolean appointmentRequestResponse = null;

   private Date appointmentRequestDate = null;

   private Date demographicUpdateDate = null;

   private Gender gender = null;

   private String   degree     = null;

   private MaritalStatus maritalStatus = null;

   private MilitaryService militaryService = null;

   private BirthRecord birthRecord = null;

   private DeathRecord deathRecord = null;

   private Integer userEnrolleeValidThrough = null;

   private VAFacility userEnrolleeSite = null;

   private String claimFolderNumber = null;

   private String mailStopReason = null;

   private Date sensitivityChangeDate = null;

   private SensitivityChangeSource sensitivityChangeSource = null;

   private VAFacility sensitivityChangeSite = null;

   private VAFacility claimFolderLocation = null;

   /* This field stores the calculated result of the most recent preferred facility site.  Please do not set it.
    * The only entry points for setting this fields are: message processing; UI update; and PCMMImport batch job process.
    * Please see PreferredFacilityServiceImpl. */
   private VAFacility mostRecentPreferredFacility = null;

   private PersonVPID vpid = null;

   // VPID_ID
   private String vpidValue = null;
   
   //EDIPI ID
   private String edipi = null;

   private PersonIdentityTraits pendingUpdatesForIdentityTraits = null; // non-persistent

   private Set otherNames = null;
   private Set otherSsns = null;
   private Name fathersName = null;
   private Name mothersName = null;
   private Set siteIdentities = null;
   // data
   private Set internalDependents = null;

   private Set internalNames = null;

   private Set internalAddresses = null;

   private Set internalPhones = null;

   private Set internalEmails = null;

   private Set internalEmergencyResponseIndicators = null;

   private Set internalAssociations = null;

   private Set internalConfidentialAddressCategories = null;

   private Set internalInsurances = null;

   private Set internalEnrollmentDeterminations = null;

   private Set internalMedicaidFactors = null;

   private Set internalPreferredLanguages = null;

   private Set internalReceivedEnrollments = null;

   private Set internalReceivedPrimaryEligibilities = null;

   private Set internalReceivedSecondaryEligibilities = null;
   
   //CR 13726
   private Set vcEligibilities = null;

   private Set internalServiceConnectionAwards = null;

   private Set internalSpecialFactors = null;

   private Set internalMSTs = null;

   private Set internalNTRs = null;

   private Set internalCDs = null;

   private Set internalSCIs = null;

   private Set internalIneligibilityFactors = null;

   private Set internalIncompetenceRulings = null;

   private Set internalDecorations = null;

   private Set internalMedalOfHonors = null;

   private Set internalShads = null;

   private Set internalMonetaryBenefitAwards = null;

   private Set internalPrisonerOfWars = null;

   private Set internalEnrollmentOverrides = null;

   private Set internalCancelDeclines = null;

   private Set internalApplications = null;

   private Set internalSsns = null;

   private Set internalEligibilityVerifications = null;

   private Set internalSignatureImages = null;

   private Set internalFeeBasis = null;

   private Set internalPreferredFacilities = null;

   private Set internalProviderAssignments = null;

   private Set internalHealthBenefitProfiles = null;

   private Map internalBeneficiaryTravels = null;

   private Map internalPatientVisitSummaries = null;

   private Map internalFinancialStatements = null;

   private Map internalInProcessFinancials = null;

   private Map internalIncomeTests = null;

   // CCR 12062 hold transient data
   private Map changeEvents = null;

   private Boolean veteran = null;

   private Boolean sensitiveRecord = null;

   private Boolean migratedEE;

   private PersonLockedReason personLockedReason = null;

   // Person has Open Cases (workflow)
   private int openCasesCount = 0;

   private String sendingFacility = null; // Non-persistent field

   private AuditInfo identityTraitsAuditInfo;

   private String mothersMaidenName;

   private Set internalEmployments = null;

   private Set internalRaces = null;

   private Set internalEthnicities = null;

   private Religion religion = null;

   private Set internalDeliveryPreferences = null;

   private boolean esrCorrelationAdded = false; //CCR12176


   /* Relatives, currently only including mother and father, each only with name populated.
    * This does NOT include spouse as that is financials only (tied to specific income year)
    */
   private Set internalRelations = null;

   private Character VOAIndicator = null;
   private boolean voaFormProcessPendingStatus = false;

   //CR 5987
   private Boolean eligibleForClassIIDental = null;

   private Date classIIDentalApplicationDueBefore = null;

   /** The earliest year for which income information can exist for a veteran. */
   public static final Integer EARLIEST_INCOME_YEAR = new Integer(1980);

   // add a person
   private Boolean needCareDueToAccident = null;
   private Boolean needCareDueToInjury = null;
   private int idmMatchType; // hold the transient value return from IdM search of ADD A PERSON.

   // add person enrollment
   private Date enrollmentSignatureDate = null;

   private SelfIdentifiedGenderIdentity selfIdentifiedGenderIdentity = null;

   //CCR 13437
   private boolean justAdded = false;



/**
    * Creates a new Person object.
    */
   public Person() {
      super();
   }

   public Person(VPIDEntityKey key) {
      super();
      this.vpidValue = key.getVPID();
   }

   protected Class getEntityKeyClass() {
      return PersonIdEntityKeyImpl.class;
   }

   // ----------------------------------------------------------------------------
   // Public method(s)
   // ----------------------------------------------------------------------------

   // convenience method
   public PersonEntityKey getPersonEntityKey() {
      return getPersonEntityKey(false);
   }

   // convenience method
   public PersonEntityKey getPersonEntityKey(boolean shouldIncludeVersion) {
      PersonEntityKey key = (PersonEntityKey)getEntityKey();
      if( key != null && !shouldIncludeVersion )
         key.disableVersionCheck();
      return key;
   }

   public Date getAppointmentRequestDate() {
      return this.appointmentRequestDate;
   }

   public void setAppointmentRequestDate(Date appointmentRequestDate) {
      this.appointmentRequestDate = appointmentRequestDate;
   }

   public Date getDemographicUpdateDate() {
      return demographicUpdateDate;
   }

   public void setDemographicUpdateDate(Date demographicUpdateDate) {
      this.demographicUpdateDate = demographicUpdateDate;
   }

   public Boolean getAppointmentRequestResponse() {
      return this.appointmentRequestResponse;
   }

   public void setAppointmentRequestResponse(Boolean appointmentRequestResponse) {
      this.appointmentRequestResponse = appointmentRequestResponse;
   }

   public Gender getGender() {
      return this.gender;
   }

   public void setGender(Gender gender) {
      this.gender = gender;
   }

   public String getDegree() {
       return this.degree;
   }

   public void setDegree(String degree) {
       this.degree = degree;
   }

   public MaritalStatus getMaritalStatus() {
      return this.maritalStatus;
   }

   public void setMaritalStatus(MaritalStatus maritalStatus) {
      this.maritalStatus = maritalStatus;
   }

   /**
    * Getter - For hibernate use only
    */
   private Set getInternalSsns() {
      if( internalSsns == null ) {
         this.internalSsns = new HashSet();
      }
      return internalSsns;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param internalSsns
    */
   private void setInternalSsns(Set internalSsns) {
      this.internalSsns = internalSsns;
   }

   /**
    * Return a Set of SSN Objects
    *
    * @return
    */
   public Set getSsns() {
      return Collections.unmodifiableSet(getInternalSsns());
   }

   /**
    * Add a SSN for this person
    *
    * @param ssn
    */
   public void addSsn(SSN ssn) {
      Validate.notNull(ssn, "SSN cannot be null");
      getInternalSsns().add(ssn);
   }

   /**
    * Remove a SSN from this Person
    *
    * @param ssn
    */
   public void removeSsn(SSN ssn) {
      Validate.notNull(ssn, "SSN cannot be null");
      getInternalSsns().remove(ssn);
   }

   private void removeAllSsns() {
      this.getInternalSsns().clear();
   }

   /**
    * Get the first official SSN from the SSN collection.
    *
    * @return
    */
   public SSN getOfficialSsn() {
      return SSN.getSSNOfType(getInternalSsns(), SSNType.CODE_ACTIVE.getName());
   }

   public SSN getPseudoSsn() {
	      return SSN.getSSNOfType(getInternalSsns(), SSNType.CODE_PSEUDO.getName());
   }

   /**
    * Return a collection of SSN of type Official.
    *
    * @return
    */
   public Set getOfficialSsns() {
      Set otherSsns = SSN.getSSNsOfType(getInternalSsns(), SSNType.CODE_ACTIVE
            .getName());
      return Collections.unmodifiableSet(otherSsns);
   }

   /**
    * Return a collection of SSN of type Other.
    *
    * @return
    */
   public Set getOtherSsns() {
      Set otherSsns = SSN.getSSNsOfType(getInternalSsns(), SSNType.CODE_ALIAS.getName());
      return Collections.unmodifiableSet(otherSsns);
   }

   public void removeOtherSsns(Set otherSsns)
   {
	   if ( otherSsns == null ) return;
       for (Iterator i = otherSsns.iterator(); i.hasNext();)
       {
    	   this.removeSsn((SSN) i.next());
       }
   }
   /**
    * Gets the Legal Name if found, otherwise returns null.
    *
    * @return returns Legal Name
    */
   public Name getLegalName() {
      return Name.getNameOfType(getInternalNames(), NameType.LEGAL_NAME.getName());
   }

   public Name getAliasName() {
	      return Name.getNameOfType(getInternalNames(), NameType.ALIAS_NAME.getName());
	   }

   public void setAliasName(Name name) {
	   Name aliasName = getAliasName();
	      if( aliasName != null ) {
	         removeName(aliasName);
	      }
	      addName(name);
	   }
   /**
    * Sets the Legal Name. If there is a legal name replaces the existing one.
    */
   public void setLegalName(Name name) {
      Name legalName = getLegalName();
      if( legalName != null ) {
         removeName(legalName);
      }
      addName(name);
   }

   /**
    * Returns a Set of Name Objects.
    *
    * @return Set - Set of Name
    */
   public Set getNames() {
      return Collections.unmodifiableSet(getInternalNames());
   }

   public Set getOtherNames() {
      Set otherNames = new HashSet(getNames());
      Name legalName = getLegalName();
      if( legalName != null ) {
         otherNames.remove(legalName);
      }
      return Collections.unmodifiableSet(otherNames);
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalNames() {
      if( this.internalNames == null ) {
         this.internalNames = new HashSet();
      }
      return this.internalNames;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalNames
    */
   private void setInternalNames(Set internalNames) {
      this.internalNames = internalNames;
   }

   /**
    * Add a Name for this person. This method takes care of Bidirectional setting of
    * Name's person.
    *
    * @param name
    */
   public void addName(Name name) {
      Validate.notNull(name, "Null Name specified.");
      this.getInternalNames().add(name);
   }

   /**
    * Removes a specified Name from this person's names collection. This method takes care
    * of Bidirectional setting of Name's person.
    *
    * @param name
    */
   public void removeName(Name name) {
      Validate.notNull(name, "Null Name specified.");
      this.getInternalNames().remove(name);
   }

   public void removeAllNames() {
      this.getInternalNames().clear();
   }

   /**
    * Returns a collection of Address Objects. If no addresses exists for this person,
    * this method will return empty Set.
    *
    * @return Set - Set of Address, Never NULL
    */
   public Set getAddresses() {
      return Collections.unmodifiableSet(getInternalAddresses());
   }

   /**
    * Returns a Address based on the entity key.
    *
    * @param identifier
    * @return Address
    */
   public Address getAddressByEntityKey(EntityKey identifier) {
      return (Address)getEntityByEntityKey(getAddresses(), identifier);
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param addresses
    */
   private void setInternalAddresses(Set addresses) {
      this.internalAddresses = addresses;
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalAddresses() {
      if( this.internalAddresses == null ) {
         this.internalAddresses = new HashSet();
      }
      return this.internalAddresses;
   }

   /**
    * Add a Address for this person. This method takes care of Bidirectional setting of
    * Address's person.
    *
    * @param address
    */
   public void addAddress(Address address) {
      Validate.notNull(address, "Null address specified.");
      getInternalAddresses().add(address);
      address.setPerson(this);
   }

   /**
    * Remove an Address from this person's Address collection. This method takes care of
    * Bidirectional setting of Address's person.
    *
    * @param address
    */
   public void removeAddress(Address address) {
      Validate.notNull(address, "Null address specified.");
      getInternalAddresses().remove(address);
   }

   /**
    * Get address of type <code>AddressType.CONFIDENTIAL</code>.
    *
    * @return Address if address of required type exists, null otherwise.
    */
   public Address getConfidentialAddress() {
      return Address.getAddressOfType(getInternalAddresses(),
            AddressType.CODE_CONFIDENTIAL_ADDRESS.getName());
   }

   /**
    * Get address of type <code>TEMPORARY_CORRESPONDENCE</code>.
    *
    * @return Address if address of required type exists, null otherwise.
    */
   public Address getTemporaryCorrespondenceAddress() {
      return Address.getAddressOfType(getInternalAddresses(),
            AddressType.CODE_TEMPORARY_CORRESPONDENCE_ADDRESS.getName());
   }

   /**
    * Get address of type <code>PERMANENT</code>.
    *
    * @return Address if address of required type exists, null otherwise.
    */
   public Address getPermanentAddress() {
      return Address.getAddressOfType(getInternalAddresses(),
            AddressType.CODE_PERMANENT_ADDRESS.getName());
   }

   /**
    * Get address of type <code>PERMANENT</code>.
    *
    * @return Address if address of required type exists, null otherwise.
    */
   public Address getResidentialAddress() {
      return Address.getAddressOfType(getInternalAddresses(),
            AddressType.CODE_RESIDENTIAL_ADDRESS.getName());
   }
   
   public void removeAllAddresses() {
      this.getInternalAddresses().clear();
   }

   /**
    * @return A collection of Phone object
    */
   public Set getPhones() {
      return Collections.unmodifiableSet(getInternalPhones());
   }

   public Phone getPhoneByEntityKey(EntityKey identifier) {
      return (Phone)getEntityByEntityKey(getPhones(), identifier);
   }

   public Phone removePhoneByEntityKey(EntityKey identifier) {
      return (Phone)removeEntityByEntityKey(getInternalPhones(), identifier);
   }

   public Phone getHomePhone() {
      return Phone.getPhoneOfType(getInternalPhones(), PhoneType.CODE_HOME.getName());
   }

   public Phone getBusinessPhone() {
      return Phone.getPhoneOfType(getInternalPhones(), PhoneType.CODE_BUSINESS.getName());
   }

   public Phone getConfidentialPhone() {
       return Phone.getPhoneOfType(getInternalPhones(), PhoneType.CODE_CONFIDENTIAL.getName());
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalPhones() {
      if( this.internalPhones == null ) {
         this.internalPhones = new HashSet();
      }
      return this.internalPhones;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param phones
    */
   private void setInternalPhones(Set phones) {
      this.internalPhones = phones;
   }

   /**
    * Add a Phone for this person. This method takes care of Bidirectional setting of
    * Phone's person.
    *
    * @param phone
    */
   public void addPhone(Phone phone) {
      Validate.notNull(phone, "Null phone specified.");
      phone.setPerson(this);
      getInternalPhones().add(phone);
   }

   /**
    * Add a collection of Phones to this person. This method takes care of Bidirectional
    * setting of Phone's person.
    *
    * @param phones
    */
   public void addAllPhones(Set phones) {
      Validate.notNull(phones, "Null set of phones specified.");
      this.setOwner(phones);
      Set internal = this.getInternalPhones();
      internal.addAll(phones);
   }

   /**
    * Remove an Phone for this person. This method takes care of Bidirectional setting of
    * Phone's person.
    *
    * @param phone
    */
   public void removePhone(Phone phone) {
      Validate.notNull(phone, "Null phone specified.");
      getInternalPhones().remove(phone);
      phone.setPerson(null);
   }

   public void removeAllPhones() {
      this.getInternalPhones().clear();
   }

   /**
    * Returns a collection of Email as array. This method guarantees to return a non-null
    * array. If no email exists for this person, this method will return zero length
    * array.
    *
    * @return Set of Email, Never NULL
    */
   public Set getEmails() {
      return Collections.unmodifiableSet(getInternalEmails());
   }

   public Email getEmailByEntityKey(EntityKey identifier) {
      return (Email)getEntityByEntityKey(getEmails(), identifier);
   }

   public Email removeEmailByEntityKey(EntityKey identifier) {
      return (Email)removeEntityByEntityKey(getInternalEmails(), identifier);
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalEmails() {
      if( this.internalEmails == null ) {
         this.internalEmails = new HashSet();
      }
      return this.internalEmails;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param emails
    */
   private void setInternalEmails(Set emails) {
      this.internalEmails = emails;
   }

   /**
    * Add an Email for this person. This method takes care of Bidirectional setting of
    * Email's person.
    *
    * @param email
    */
   public void addEmail(Email email) {
      Validate.notNull(email, "Null email specified.");
      getInternalEmails().add(email);
      email.setPerson(this);
   }

   /**
    * Add an Email for this person. This method takes care of Bidirectional setting of
    * Email's person.
    *
    * @param email
    */
   public void addAllEmails(Set emails) {
      Validate.notNull(emails, "Empty set of emails specified.");

      this.setOwner(emails);
      Set internal = this.getInternalEmails();
      internal.addAll(emails);
   }

   /**
    * Remove an Email for this person. This method takes care of Bidirectional setting of
    * Email's person.
    *
    * @param email
    */
   public void removeEmail(Email email) {
      Validate.notNull(email, "Null Email specified.");
      email.setPerson(null);
      getInternalEmails().remove(email);
   }

   public void removeAllEmails() {
      this.getInternalEmails().clear();
   }

   /**
    * Returns a collection of EmergencyResponseIndicator as array. This method guarantees
    * to return a non-null array. If no emergencyResponseIndicator exists for this person,
    * this method will return zero length array.
    *
    * @return Set of EmergencyResponseIndicator, Never NULL
    */
   public Set getEmergencyResponseIndicators() {
      return Collections.unmodifiableSet(getInternalEmergencyResponseIndicators());
   }

   public EmergencyResponseIndicator getEmergencyResponseIndicatorByEntityKey(
         EntityKey identifier) {
      return (EmergencyResponseIndicator)getEntityByEntityKey(
            getEmergencyResponseIndicators(), identifier);
   }

   public EmergencyResponseIndicator removeEmergencyResponseIndicatorByEntityKey(
         EntityKey identifier) {
      return (EmergencyResponseIndicator)removeEntityByEntityKey(
            getInternalEmergencyResponseIndicators(), identifier);
   }

   /**
    * Returns a collection of ConfidentialAddressCategory objects. If no objects exists
    * for this person, this method will return empty Set.
    *
    * @return Set - Set of ConfidentialAddressCategory objects
    */
   public Set getConfidentialAddressCategories() {
       return getInternalConfidentialAddressCategories();
   }

   /**
    * Setter - for hibernate use only.
    */
   private void setInternalConfidentialAddressCategories(Set confidentialAddressCategories) {
      this.internalConfidentialAddressCategories = confidentialAddressCategories;
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalConfidentialAddressCategories() {
      if( this.internalConfidentialAddressCategories == null ) {
         this.internalConfidentialAddressCategories = new HashSet();
      }
      return this.internalConfidentialAddressCategories;
   }

   /**
    * Add a ConfidentialAddressCategory object with the specified type for this person. No
    * op if a ConfidentialAddressCategory object with the specified type already exists
    * for this person.
    *
    * @param address
    */
   public void addConfidentialAddressCategory(ConfidentialAddressCategoryType type) {
      Validate.notNull(type, "Null ConfidentialAddressCategoryType specified");
      ConfidentialAddressCategory cat = getConfidentialAddressCategory(type);
      if( cat != null )
         return;
      cat = new ConfidentialAddressCategory();
      cat.setPerson(this);
      cat.setType(type);
      getInternalConfidentialAddressCategories().add(cat);
   }

   /**
    * Remove the ConfidentialAddressCategory object with the specified type for this
    * person
    */
   public void removeConfidentialAddressCategory(ConfidentialAddressCategoryType type) {
      Validate.notNull(type, "Null ConfidentialAddressCategoryType specified");
      ConfidentialAddressCategory cat = getConfidentialAddressCategory(type);
      if( cat != null )
         getInternalConfidentialAddressCategories().remove(cat);
   }

   public void removeAllConfidentialAddressCategories() {
      getConfidentialAddressCategories().clear();
   }

   private ConfidentialAddressCategory getConfidentialAddressCategory(
         ConfidentialAddressCategoryType type) {
      Validate.notNull(type, "Null ConfidentialAddressCategoryType specified");
      Iterator iter = this.getInternalConfidentialAddressCategories().iterator();
      while( iter.hasNext() ) {
         ConfidentialAddressCategory cat = (ConfidentialAddressCategory)iter.next();
         if( type.getCode().equals(cat.getType().getCode()) )
            return cat;
      }
      return null;

   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalEmergencyResponseIndicators() {
      if( this.internalEmergencyResponseIndicators == null ) {
         this.internalEmergencyResponseIndicators = new HashSet();
      }
      return this.internalEmergencyResponseIndicators;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param emergencyResponseIndicators
    */
   private void setInternalEmergencyResponseIndicators(Set emergencyResponseIndicators) {
      this.internalEmergencyResponseIndicators = emergencyResponseIndicators;
   }

   /**
    * Add an EmergencyResponseIndicator for this person. This method takes care of
    * Bidirectional setting of EmergencyResponseIndicator's person.
    *
    * @param emergencyResponseIndicator
    */
   public void addEmergencyResponseIndicator(
         EmergencyResponseIndicator emergencyResponseIndicator) {
      Validate.notNull(emergencyResponseIndicator,
            "Null emergencyResponseIndicator specified.");
      getInternalEmergencyResponseIndicators().add(emergencyResponseIndicator);
      emergencyResponseIndicator.setPerson(this);
   }

   /**
    * Add an EmergencyResponseIndicator for this person. This method takes care of
    * Bidirectional setting of EmergencyResponseIndicator's person.
    *
    * @param emergencyResponseIndicator
    */
   public void addAllEmergencyResponseIndicators(Set emergencyResponseIndicators) {
      Validate.notNull(emergencyResponseIndicators,
            "Empty set of emergencyResponseIndicators specified.");

      this.setOwner(emergencyResponseIndicators);
      Set internal = this.getInternalEmergencyResponseIndicators();
      internal.addAll(emergencyResponseIndicators);
   }

   /**
    * Remove an EmergencyResponseIndicator for this person. This method takes care of
    * Bidirectional setting of EmergencyResponseIndicator's person.
    *
    * @param emergencyResponseIndicator
    */
   public void removeEmergencyResponseIndicator(
         EmergencyResponseIndicator emergencyResponseIndicator) {
      Validate.notNull(emergencyResponseIndicator,
            "Null EmergencyResponseIndicator specified.");
      emergencyResponseIndicator.setPerson(null);
      getInternalEmergencyResponseIndicators().remove(emergencyResponseIndicator);
   }

   public void removeAllEmergencyResponseIndicators() {
      this.getInternalEmergencyResponseIndicators().clear();
   }

   /**
    * Returns a unmodifiable collection of Association Objects.
    *
    * @return Set - Set of Association, Never NULL
    */
   public Set getAllAssociations() {
     return Collections.unmodifiableSet(this.getInternalAssociations());
  }

  /**
   * Returns a unmodifiable collection of Active Association Objects.
   *
   * @return Set - Set of Association, Never NULL
   */

   public Set getAssociations() {

       Set activeAssocs = new HashSet();
       Iterator iter = getInternalAssociations().iterator();
       while (iter.hasNext()) {
           Association assoc = (Association)iter.next();
           if (assoc.isExpired()==false) {
               activeAssocs.add(assoc);
           }
       }

      return Collections.unmodifiableSet(activeAssocs);
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalAssociations() {
      if( this.internalAssociations == null ) {
         this.internalAssociations = new HashSet();
      }
      return this.internalAssociations;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param associations
    */
   private void setInternalAssociations(Set associations) {
      this.internalAssociations = associations;
   }

   /**
    * Add an Association for this person. This method takes care of Bidirectional setting
    * of Association's person.
    *
    * @param association
    */
   public void addAssociation(Association association) {
      Validate.notNull(association, "Null association specified.");
      getInternalAssociations().add(association);
      association.setPerson(this);
   }

   /**
    * Add a collection of Associations to this person.
    *
    * @param associations
    *           A collection of association
    */
   public void addAllAssociations(Set associations) {
      Validate.notEmpty(associations, "Associations cannot be null or empty");

      // Call addInsurance to handle bidirectional relationship
      for( Iterator i = associations.iterator(); i.hasNext(); ) {
         Object association = i.next();
         if( association instanceof Association ) {
            this.addAssociation((Association)association);
         }
      }
   }

   /**
    * Remove an Association for this person. This method takes care of Bidirectional
    * setting of Association's person.
    *
    * @param association
    */
   public void removeAssociation(Association association) {
      Validate.notNull(association, "Null association specified.");
      getInternalAssociations().remove(association);
   }

   public Association getAssociationByEntityKey(EntityKey identifier) {
      return (Association)getEntityByEntityKey(getInternalAssociations(), identifier);
   }

   public Association getEmergencyContact()
   {
	   return Association.getAssociationOfType(getInternalAssociations(), AssociationType.CODE_EMERGENCY_CONTACT.getCode());
   }
   public Association getPOA() {
	   return Association.getAssociationOfType(getInternalAssociations(), AssociationType.CODE_POWER_OF_ATTORNEY.getCode());
   }

   public Association getVAGuardian() {
       return Association.getAssociationOfType(getInternalAssociations(), AssociationType.CODE_GUARDIAN_VA.getCode());
   }

   public Association removeAssociationByEntityKey(EntityKey identifier) {
      return (Association)removeEntityByEntityKey(getInternalAssociations(), identifier);
   }

   public void removeAllAssociations() {
      getInternalAssociations().clear();
   }

   /**
    * Returns a collection of InsurancePolicy Objects.
    *
    * @return Set - Set if InsurancePolicy
    */
   public Set getInsurances() {
      return Collections.unmodifiableSet(this.getInternalInsurances());
   }

   /**
    * Returns a collection of Medicare Objects.
    *
    * @return Set - Set of Medicare objects.
    */
   public Set getMedicareInsurances() {
      Set returnSet = new HashSet();
      for( Iterator iterator = internalInsurances.iterator(); iterator.hasNext(); ) {
         Object insuranceObject = iterator.next();
         if( Medicare.class.isAssignableFrom(insuranceObject.getClass()) ) {
            returnSet.add(insuranceObject);
         }
      }
      return Collections.unmodifiableSet(returnSet);
   }

   /**
    * Returns a collection of PrivateInsurance Objects.
    *
    * @return Set - Set of PrivateInsurance objecs.
    */
   public Set getPrivateInsurances() {
      Set returnSet = new HashSet();
      for( Iterator iterator = internalInsurances.iterator(); iterator.hasNext(); ) {
         Object insuranceObject = iterator.next();
         if( PrivateInsurance.class.isAssignableFrom(insuranceObject.getClass()) ) {
            returnSet.add(insuranceObject);
         }
      }
      return Collections.unmodifiableSet(returnSet);
   }

   public InsurancePolicy getInsuranceByEntityKey(EntityKey identifier) {
      return (InsurancePolicy)getEntityByEntityKey(getInsurances(), identifier);
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalInsurances() {
      if( this.internalInsurances == null ) {
         this.internalInsurances = new HashSet();
      }
      return this.internalInsurances;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalInsurances
    */
   private void setInternalInsurances(Set internalInsurances) {
      this.internalInsurances = internalInsurances;
   }

   /**
    * Add an InsurancePolicy for this person. This method takes care of Bidirectional
    * setting of InsurancePolicy's person.
    *
    * @param policy
    *           An insurance policy to add
    */
   public void addInsurance(InsurancePolicy policy) {
      Validate.notNull(policy, "Insurance policy cannot be null");
      getInternalInsurances().add(policy);
      policy.setPerson(this);
   }

   /**
    * Add a list of InsurancePolicy to this person.
    *
    * @param policies
    *           A collection of policies
    */
   public void addAllInsurances(Set policies) {
      Validate.notEmpty(policies, "Insurance policies cannot be null or empty");

      // Call addInsurance to handle bidirectional relationship
      for( Iterator i = policies.iterator(); i.hasNext(); ) {
         Object policy = i.next();
         if( policy instanceof InsurancePolicy ) {
            this.addInsurance((InsurancePolicy)policy);
         }
      }
   }

   /**
    * Remove an InsurancePolicy for this person. This method takes care of Bidirectional
    * setting of InsurancePolicy's person.
    *
    * @param insurance
    */
   public void removeInsurance(InsurancePolicy insurance) {
      Validate.notNull(insurance, "Insurance policy cannot be null");
      getInternalInsurances().remove(insurance);
   }

   /**
    * Remove Insuarnce by entity Key
    *
    * @param identifier
    * @return
    */
   public InsurancePolicy removeInsuranceByEntityKey(EntityKey identifier) {
      return (InsurancePolicy)removeEntityByEntityKey(getInternalInsurances(), identifier);
   }

   public void removeAllInsurances() {
      this.getInternalInsurances().clear();
   }

   /**
    * Getter - For hibernate use only
    */
   private Set getInternalReceivedPrimaryEligibilities() {
      if( this.internalReceivedPrimaryEligibilities == null ) {
         this.internalReceivedPrimaryEligibilities = new HashSet();
      }
      return this.internalReceivedPrimaryEligibilities;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param internalReceivedPrimaryEligibilities
    */
   private void setInternalReceivedPrimaryEligibilities(
         Set internalReceivedPrimaryEligibilities) {
      this.internalReceivedPrimaryEligibilities = internalReceivedPrimaryEligibilities;
   }

   /**
    * Get the ReceivedEligibility of type Primary
    *
    * @return
    */
   public ReceivedEligibility getReceivedPrimaryEligibility() {
      Set eligibilities = getInternalReceivedPrimaryEligibilities();
      if( eligibilities.size() > 0 ) {
         return (ReceivedEligibility)this.internalReceivedPrimaryEligibilities.iterator()
               .next();
      }
      return null;
   }

   /**
    * Set the ReceivedEligibility of type Primary
    *
    * @param primaryEligibility
    */
   public void setReceivedPrimaryEligiblity(ReceivedEligibility primaryEligibility) {
      Set eligibilities = getInternalReceivedPrimaryEligibilities();
      eligibilities.clear();
      if( primaryEligibility != null ) {
         addReceivedPrimaryEligibility(primaryEligibility);
      }
   }

   /**
    * Add a ReceivedEligibility of type Primary
    *
    * @param primaryEligibility
    */
   private void addReceivedPrimaryEligibility(ReceivedEligibility primaryEligibility) {
      Validate.notNull(primaryEligibility, "Primary eligibility cannot be null");
      getInternalReceivedPrimaryEligibilities().add(primaryEligibility);
      primaryEligibility.setPrimary();
      primaryEligibility.setPerson(this);
   }

   /**
    * Getter - For hibernate use only
    */
   private Set getInternalReceivedSecondaryEligibilities() {
      if( this.internalReceivedSecondaryEligibilities == null ) {
         this.internalReceivedSecondaryEligibilities = new HashSet();
      }
      return this.internalReceivedSecondaryEligibilities;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param internalReceivedSecondaryEligibilities
    */
   private void setInternalReceivedSecondaryEligibilities(
         Set internalReceivedSecondaryEligibilities) {
      this.internalReceivedSecondaryEligibilities = internalReceivedSecondaryEligibilities;
   }

   /**
    * Getter - For hibernate use only
    */
   private Set getVcEligibilities() {
	  if( this.vcEligibilities == null ) {
	          this.vcEligibilities = new HashSet();
	  }
	  return this.vcEligibilities;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param vcEligibilities
    */
   private void setVcEligibilities(Set vcEligibilities) {
		this.vcEligibilities = vcEligibilities;
   }

   /**
    * Collection of Received Eligibilities of type Secondary.
    *
    * @return Set - Set of ReceivedEligbility
    */
   public Set getReceivedSecondaryEligibilities() {
      return Collections.unmodifiableSet(getInternalReceivedSecondaryEligibilities());
   }

   /**
    * Add a ReceivedEnrollment of type Secondary
    *
    * @param secondaryEligibility
    */
   public void addReceivedSecondaryEligibility(ReceivedEligibility secondaryEligibility) {
      Validate.notNull(secondaryEligibility, "secondary eligibility cannot be null");
      secondaryEligibility.setSecondary();
      secondaryEligibility.setPerson(this);
      getInternalReceivedSecondaryEligibilities().add(secondaryEligibility);
   }

   /**
    * Remove a ReceivedEnrollment of type Secondary
    */
   public void removeReceivedSecondaryEligibility(ReceivedEligibility secondaryEligibility) {
      Validate.notNull(secondaryEligibility, "Secondary eligibility cannot be null");
      getInternalReceivedSecondaryEligibilities().remove(secondaryEligibility);
   }

   public void removeAllReceivedSecondaryEligibilities() {
      this.getInternalReceivedSecondaryEligibilities().clear();
   }

   /**
    * Getter for internalReceivedEnrollments
    */
   private Set getInternalReceivedEnrollments() {
      if( this.internalReceivedEnrollments == null ) {
         this.internalReceivedEnrollments = new HashSet();
      }
      return this.internalReceivedEnrollments;
   }

   /**
    * Setter - for hibernate use only
    *
    * @param internalReceivedEnrollments
    */
   private void setInternalReceivedEnrollments(Set internalReceivedEnrollments) {
      this.internalReceivedEnrollments = internalReceivedEnrollments;
   }

   /**
    * Return a ReceivedEnrollment for this Person.
    */
   public ReceivedEnrollment getReceivedEnrollment() {
      Set enrollments = getInternalReceivedEnrollments();
      if( enrollments.size() > 0 ) {
         return (ReceivedEnrollment)this.internalReceivedEnrollments.iterator().next();
      }
      return null;
   }

   /**
    * Set the ReceivedEnrollment for this Person.
    *
    * @param receivedEnrollment
    */
   public void setReceivedEnrollment(ReceivedEnrollment receivedEnrollment) {
      Set enrollments = getInternalReceivedEnrollments();
      enrollments.clear();
      if( receivedEnrollment != null ) {
         enrollments.add(receivedEnrollment);
         receivedEnrollment.setPerson(this);
      }
   }

   /**
    * Getter - For hibernate use only
    *
    * @return
    */
   private Set getInternalServiceConnectionAwards() {
      if( this.internalServiceConnectionAwards == null ) {
         this.internalServiceConnectionAwards = new HashSet();
      }
      return this.internalServiceConnectionAwards;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param internalServiceConnectionAwards
    */
   private void setInternalServiceConnectionAwards(Set internalServiceConnectionAwards) {
      this.internalServiceConnectionAwards = internalServiceConnectionAwards;
   }

   /**
    * Get the ServiceConnectionAward for this Person
    *
    * @return ServiceConnectionAward
    */
   public ServiceConnectionAward getServiceConnectionAward() {
      Set scAwards = getInternalServiceConnectionAwards();
      if( scAwards.size() > 0 ) {
         return (ServiceConnectionAward)this.internalServiceConnectionAwards.iterator()
               .next();
      }
      return null;
   }

   /**
    * Set the ServiceConnectionAward for this Person
    *
    * @param serviceConnectionAward
    */
   public void setServiceConnectionAward(ServiceConnectionAward serviceConnectionAward) {
      Set scAwards = getInternalServiceConnectionAwards();
      scAwards.clear();

      if( serviceConnectionAward != null ) {
         getInternalServiceConnectionAwards().add(serviceConnectionAward);
         serviceConnectionAward.setPerson(this);
      }
   }

   private Set getInternalPrisonerOfWars() {
      if( this.internalPrisonerOfWars == null ) {
         this.internalPrisonerOfWars = new HashSet();
      }
      return this.internalPrisonerOfWars;
   }

   private void setInternalPrisonerOfWars(Set prisonerOfWars) {
      this.internalPrisonerOfWars = prisonerOfWars;
   }

   public PrisonerOfWar getPrisonerOfWar() {
      Set prisonerOfWars = getInternalPrisonerOfWars();
      return prisonerOfWars.size() > 0 ? (PrisonerOfWar)prisonerOfWars.iterator().next()
            : null;
   }

   public void setPrisonerOfWar(PrisonerOfWar prisonerOfWar) {
      Set prisonerOfWars = getInternalPrisonerOfWars();
      Iterator iter = prisonerOfWars.iterator();
      if( iter.hasNext() ) {
         PrisonerOfWar o = (PrisonerOfWar)iter.next();
         o.setPerson(null);
      }
      prisonerOfWars.clear();

      if( prisonerOfWar != null ) {
         prisonerOfWars.add(prisonerOfWar);
         prisonerOfWar.setPerson(this);
      }
   }

   private Set getInternalHealthBenefitProfiles() {
      if( internalHealthBenefitProfiles == null ) {
         this.internalHealthBenefitProfiles = new HashSet();
      }
      return this.internalHealthBenefitProfiles;
   }

   private void setInternalHealthBenefitProfiles(Set internalHealthBenefitProfiles) {
      this.internalHealthBenefitProfiles = internalHealthBenefitProfiles;
   }

   public HealthBenefitProfile getHealthBenefitProfile() {
			Set hbps = getInternalHealthBenefitProfiles();
			if (hbps.size() == 0) {
				HealthBenefitProfile hbp = new HealthBenefitProfile();
				hbp.setPerson(this);
				setHealthBenefitProfile(hbp);
			}
			return (HealthBenefitProfile) hbps.iterator().next();
   }

   public void setHealthBenefitProfile(HealthBenefitProfile healthBenefitProfile) {
      Set hbps = getInternalHealthBenefitProfiles();
      Iterator iter = hbps.iterator();
      if( iter.hasNext() ) {
    	  HealthBenefitProfile hbp = (HealthBenefitProfile)iter.next();
    	  hbp.setPerson(null);
      }

      hbps.clear();
      if( healthBenefitProfile != null ) {
    	  hbps.add(healthBenefitProfile);
    	  healthBenefitProfile.setPerson(this);
      }
   }

   private void setInternalSpecialFactors(Set specialFactors) {
      this.internalSpecialFactors = specialFactors;
   }

   private Set getInternalSpecialFactors() {
      if( this.internalSpecialFactors == null ) {
         this.internalSpecialFactors = new HashSet();
      }
      return this.internalSpecialFactors;
   }

   public Set getSpecialFactors() {
      return UnmodifiableSet.decorate(getInternalSpecialFactors());
   }

   public void addSpecialFactor(SpecialFactor specialFactor) {
      getInternalSpecialFactors().add(specialFactor);
      specialFactor.setPerson(this);
   }

   public void removeSpecialFactor(SpecialFactor specialFactor) {
      Validate.notNull(specialFactor, "Null Special Factor specified.");
      getInternalSpecialFactors().remove(specialFactor);
      specialFactor.setPerson(null);
   }

   public SpecialFactor getSpecialFactorByEntityKey(EntityKey identifier) {
      return (SpecialFactor)getEntityByEntityKey(getSpecialFactors(), identifier);
   }

   public SpecialFactor removeSpecialFactorByEntityKey(EntityKey identifier) {
      return (SpecialFactor)removeEntityByEntityKey(getInternalSpecialFactors(),
            identifier);
   }

   public SpecialFactor getSpecialFactorByType(Class specialFactorType) {
      return (SpecialFactor)CollectionUtils.getObjectOfClassType(getSpecialFactors(),
            specialFactorType);
   }

   public SpecialFactor removeSpecialFactorByType(Class specialFactorType) {
      return (SpecialFactor)CollectionUtils.removeObjectOfClassType(
            getInternalSpecialFactors(), specialFactorType);
   }

   public void removeAllSpecialFactors() {
      getInternalSpecialFactors().clear();
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalMSTs() {
      if( this.internalMSTs == null ) {
         this.internalMSTs = new HashSet();
      }
      return this.internalMSTs;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalMSTs
    */
   private void setInternalMSTs(Set internalMSTs) {
      this.internalMSTs = internalMSTs;
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalCDs() {
      if( this.internalCDs == null ) {
         this.internalCDs = new HashSet();
      }
      return this.internalCDs;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalCDs
    */
   private void setInternalCDs(Set internalCDs) {
      this.internalCDs = internalCDs;
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalNTRs() {
      if( this.internalNTRs == null ) {
         this.internalNTRs = new HashSet();
      }
      return this.internalNTRs;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalNTRs
    */
   private void setInternalNTRs(Set internalNTRs) {
      this.internalNTRs = internalNTRs;
   }

   /**
    * Getter - for hibernate use only.
    *
    * @return
    */
   private Set getInternalSCIs() {
      if( this.internalSCIs == null ) {
         this.internalSCIs = new HashSet();
      }
      return this.internalSCIs;
   }

   /**
    * Setter - for hibernate use only.
    *
    * @param internalSCIs
    */
   private void setInternalSCIs(Set internalSCIs) {
      this.internalSCIs = internalSCIs;
   }


   public Set getClinicalDeterminations() {
      Set allClinicalDeterminations = new HashSet();
      allClinicalDeterminations.addAll(getInternalCDs());
      allClinicalDeterminations.addAll(getInternalMSTs());
      allClinicalDeterminations.addAll(getInternalNTRs());
      allClinicalDeterminations.addAll(getInternalSCIs());
      return Collections.unmodifiableSet(allClinicalDeterminations);
   }

   public void addClinicalDetermination(ClinicalDetermination clinicalDetermination) {
      Validate.notNull(clinicalDetermination, "Null ClinicalDetermination specified.");
      clinicalDetermination.setPerson(this);
      if( clinicalDetermination instanceof CatastrophicDisability ) {
         getInternalCDs().add(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof MilitarySexualTrauma ) {
         getInternalMSTs().add(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof NoseThroatRadium ) {
         getInternalNTRs().add(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof SpinalCordInjury ) {
          getInternalSCIs().add(clinicalDetermination);
       }
   }

   public void removeClinicalDetermination(ClinicalDetermination clinicalDetermination) {
      Validate.notNull(clinicalDetermination, "Null clinicalDetermination specified.");
      if( clinicalDetermination instanceof CatastrophicDisability ) {
         getInternalCDs().remove(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof MilitarySexualTrauma ) {
         getInternalMSTs().remove(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof NoseThroatRadium ) {
         getInternalNTRs().remove(clinicalDetermination);
      }
      else if( clinicalDetermination instanceof SpinalCordInjury ) {
          getInternalSCIs().remove(clinicalDetermination);
       }
      clinicalDetermination.setPerson(null);
   }

   public void removeAllClinicalDeterminations() {
      this.getInternalCDs().clear();
      this.getInternalMSTs().clear();
      this.getInternalNTRs().clear();
      this.getInternalSCIs().clear();
   }

   public ClinicalDetermination getClinicalDeterminationByEntityKey(EntityKey identifier) {
      return (ClinicalDetermination)getEntityByEntityKey(getClinicalDeterminations(),
            identifier);
   }

   public ClinicalDetermination removeClinicalDeterminationByEntityKey(
         EntityKey identifier) {
      ClinicalDetermination match = (ClinicalDetermination)removeEntityByEntityKey(
            getInternalCDs(), identifier);
      if( match == null )
         match = (ClinicalDetermination)removeEntityByEntityKey(getInternalMSTs(),
               identifier);
      if( match == null )
         match = (ClinicalDetermination)removeEntityByEntityKey(getInternalNTRs(),
               identifier);
      if( match == null )
          match = (ClinicalDetermination)removeEntityByEntityKey(getInternalSCIs(),
                identifier);
      return match;
   }

   public ClinicalDetermination getClinicalDeterminationByType(
         Class clinicalDeterminationType) {
      return (ClinicalDetermination)CollectionUtils.getObjectOfClassType(
            getClinicalDeterminations(), clinicalDeterminationType);
   }

   public ClinicalDetermination removeClinicalDeterminationByType(
         Class clinicalDeterminationType) {
      if( CatastrophicDisability.class.isAssignableFrom(clinicalDeterminationType) ) {
         return (ClinicalDetermination)CollectionUtils.removeObjectOfClassType(
               getInternalCDs(), clinicalDeterminationType);
      }
      else if( MilitarySexualTrauma.class.isAssignableFrom(clinicalDeterminationType) ) {
         return (ClinicalDetermination)CollectionUtils.removeObjectOfClassType(
               getInternalMSTs(), clinicalDeterminationType);
      }
      else if( NoseThroatRadium.class.isAssignableFrom(clinicalDeterminationType) ) {
         return (ClinicalDetermination)CollectionUtils.removeObjectOfClassType(
               getInternalNTRs(), clinicalDeterminationType);
      }
      else if( SpinalCordInjury.class.isAssignableFrom(clinicalDeterminationType) ) {
          return (ClinicalDetermination)CollectionUtils.removeObjectOfClassType(
                getInternalSCIs(), clinicalDeterminationType);
       }
      else
         return null;
   }

   public CatastrophicDisability getCatastrophicDisability() {
      return (CatastrophicDisability)getClinicalDeterminationByType(CatastrophicDisability.class);
   }

   public MilitarySexualTrauma getMilitarySexualTrauma() {
      return (MilitarySexualTrauma)getClinicalDeterminationByType(MilitarySexualTrauma.class);
   }

   public NoseThroatRadium getNoseThroatRadium() {
      return (NoseThroatRadium)getClinicalDeterminationByType(NoseThroatRadium.class);
   }

   public SpinalCordInjury getSpinalCordInjury() {
       return (SpinalCordInjury)getClinicalDeterminationByType(SpinalCordInjury.class);
    }

   /**
    * Set methods added for Person Merge
    *
    * @param catastrophicDisability
    */
   public void setCatastrophicDisability(CatastrophicDisability catastrophicDisability) {
      if( catastrophicDisability == null ) {
         removeClinicalDeterminationByType(CatastrophicDisability.class);
      }
      else {
         removeAndAddClinicalDetermination(catastrophicDisability);
      }
   }

   public void setMilitarySexualTrauma(MilitarySexualTrauma militarySexualTrauma) {
      if( militarySexualTrauma == null ) {
         removeClinicalDeterminationByType(MilitarySexualTrauma.class);
      }
      else {
         removeAndAddClinicalDetermination(militarySexualTrauma);
      }
   }

   public void setNoseThroatRadium(NoseThroatRadium noseThroatRadium) {
      if( noseThroatRadium == null ) {
         removeClinicalDeterminationByType(NoseThroatRadium.class);
      }
      else {
         removeAndAddClinicalDetermination(noseThroatRadium);
      }
   }

   public void setSpinalCordInjury(SpinalCordInjury spinalCordInjury) {
       if( spinalCordInjury == null ) {
          removeClinicalDeterminationByType(SpinalCordInjury.class);
       }
       else {
          removeAndAddClinicalDetermination(spinalCordInjury);
       }
    }

  /**
    * Remove and add CD as we only support one instance of each type
    *
    * @param clinicalDetermination
    */
   private void removeAndAddClinicalDetermination(
         ClinicalDetermination clinicalDetermination) {
      ClinicalDetermination old = getClinicalDeterminationByType(clinicalDetermination
            .getClass());
      if( old == null ) {
         addClinicalDetermination(clinicalDetermination);
      }
      else if( old != clinicalDetermination ) {
         removeClinicalDetermination(old);
         addClinicalDetermination(clinicalDetermination);
      }
   }

   private Map getInternalBeneficiaryTravels() {
      if( this.internalBeneficiaryTravels == null ) {
         this.internalBeneficiaryTravels = new HashMap();
      }
      return this.internalBeneficiaryTravels;
   }

   private void setInternalBeneficiaryTravels(Map internalBeneficiaryTravels) {
      this.internalBeneficiaryTravels = internalBeneficiaryTravels;
   }

   public Map getBeneficiaryTravels() {
      return Collections.unmodifiableMap(getInternalBeneficiaryTravels());
   }

   public Set getBeneficiaryTravels(Integer incomeYear) {
      Validate.notNull(incomeYear, "Income year can not be null");
      Set s = new HashSet();
      Iterator iter = getBeneficiaryTravels().values().iterator();
      while( iter.hasNext() ) {
         BeneficiaryTravel t = (BeneficiaryTravel)iter.next();
         if( incomeYear.equals(t.getYear()) )
            s.add(t);
      }
      return Collections.unmodifiableSet(s);
   }

   public BeneficiaryTravel getBeneficiaryTravel(Integer year, VAFacility facilityVisited) {
      SiteYear siteYear = new SiteYear(year, facilityVisited);
      return (BeneficiaryTravel)this.getInternalBeneficiaryTravels().get(siteYear);
   }

   public void setBeneficiaryTravel(Integer year, VAFacility facilityVisited,
         BeneficiaryTravel bTravel) {
      Validate.notNull(year, "Beneficiary Travel year  cannot be null");
      Validate.notNull(facilityVisited, "facility visited cannot be null");
      BeneficiaryTravel currentBTravel = this.getBeneficiaryTravel(year, facilityVisited);
      if( currentBTravel != bTravel ) {
         SiteYear siteYear = new SiteYear(year, facilityVisited);
         if( currentBTravel != null ) {
            getInternalBeneficiaryTravels().remove(siteYear);
            currentBTravel.setPerson(null);
         }
         if( bTravel != null ) {
            bTravel.setFacilityVisited(siteYear.getFacility());
            bTravel.setYear(siteYear.getYear());
            bTravel.setPerson(this);
            getInternalBeneficiaryTravels().put(siteYear, bTravel);
         }
      }
   }

   private Map getInternalPatientVisitSummaries() {
      if( this.internalPatientVisitSummaries == null ) {
         this.internalPatientVisitSummaries = new HashMap();
      }
      return this.internalPatientVisitSummaries;
   }

   private void setInternalPatientVisitSummaries(Map internalPatientVisitSummaries) {
      this.internalPatientVisitSummaries = internalPatientVisitSummaries;
   }

   public Map getPatientVisitSummaries() {
      return Collections.unmodifiableMap(getInternalPatientVisitSummaries());
   }

   public Set getPatientVisitSummaries(Integer incomeYear) {
      return PatientVisitSummary.getPatientVisitSummaries(
            getInternalPatientVisitSummaries().values(), incomeYear);
   }

   public Set getPatientVisitSummaries(VAFacility facilityVisited) {
      return PatientVisitSummary.getPatientVisitSummaries(
            getInternalPatientVisitSummaries().values(), facilityVisited);
   }

   public PatientVisitSummary getPatientVisitSummary(Integer incomeYear,
         VAFacility facilityVisited) {
      SiteYear siteYear = new SiteYear(incomeYear, facilityVisited);
      return (PatientVisitSummary)this.getInternalPatientVisitSummaries().get(siteYear);
   }

   /**
    * New method added for using in Person merge service - uses the existing set method
    *
    * @param facilityVisited
    */
   public void removePatientVisitSummary(VAFacility facilityVisited) {
      Set set = getPatientVisitSummaries(facilityVisited);
      for( Iterator i = set.iterator(); i.hasNext(); ) {
         PatientVisitSummary visitSummary = (PatientVisitSummary)i.next();
         setPatientVisitSummary(visitSummary.getIncomeYear(), visitSummary
               .getFacilityVisited(), null);
      }
   }

   /**
    * Uses the existing set method - used in person merge service
    *
    * @param visitSummary
    */
   public void addPatientVisitSummary(PatientVisitSummary visitSummary) {
      setPatientVisitSummary(visitSummary.getIncomeYear(), visitSummary
            .getFacilityVisited(), visitSummary);
   }

   public void setPatientVisitSummary(Integer incomeYear, VAFacility facilityVisited,
         PatientVisitSummary visitSummary) {
      Validate.notNull(incomeYear, "Income year  cannot be null");
      Validate.notNull(facilityVisited, "facility visited cannot be null");
      PatientVisitSummary currentVisitSummary = this.getPatientVisitSummary(incomeYear,
            facilityVisited);
      if( currentVisitSummary != visitSummary ) {
         SiteYear siteYear = new SiteYear(incomeYear, facilityVisited);
         if( currentVisitSummary != null ) {
            getInternalPatientVisitSummaries().remove(siteYear);
            currentVisitSummary.setPerson(null);
         }
         if( visitSummary != null ) {
            visitSummary.setFacilityVisited(siteYear.getFacility());
            visitSummary.setIncomeYear(siteYear.getYear());
            visitSummary.setPerson(this);
            getInternalPatientVisitSummaries().put(siteYear, visitSummary);
         }
      }
   }

   private Set getInternalFeeBasis() {
      if( this.internalFeeBasis == null ) {
         this.internalFeeBasis = new HashSet();
      }
      return this.internalFeeBasis;
   }

   private void setInternalFeeBasis(Set internalFeeBasis) {
      this.internalFeeBasis = internalFeeBasis;
   }

   public Set getFeeBasis() {
      return Collections.unmodifiableSet(getInternalFeeBasis());
   }

   public Set getFeeBasis(VAFacility reportedSite) {
       Validate.notNull(reportedSite, "reported Site cannot be null");
       Set siteFeeBasis = new HashSet();
       for (Iterator i= getInternalFeeBasis().iterator(); i.hasNext();){
           FeeBasis feeBasis = (FeeBasis)i.next();
           if (reportedSite.equals(feeBasis.getReportSite())){
               siteFeeBasis.add(feeBasis);
           }
       }
       return siteFeeBasis;
   }

   public void addFeeBasis(FeeBasis feeBasis) {
       if (feeBasis != null){
           getInternalFeeBasis().add(feeBasis);
           feeBasis.setPerson(this);
       }
   }

   public void removeFeeBasis(FeeBasis feeBasis) {
       this.getInternalFeeBasis().remove(feeBasis);
   }

   public void removeFeeBasis(VAFacility facilityVisited) {
       Set set = getFeeBasis(facilityVisited);
       for( Iterator i = set.iterator(); i.hasNext(); ) {
           FeeBasis feeBasis = (FeeBasis)i.next();
           removeFeeBasis(feeBasis);
       }
    }

   public void removeAllFeeBasis() {
      this.getInternalFeeBasis().clear();
   }


   private Set getInternalIneligibilityFactors() {
      if( internalIneligibilityFactors == null ) {
         this.internalIneligibilityFactors = new HashSet();
      }
      return this.internalIneligibilityFactors;
   }

   private void setInternalIneligibilityFactors(Set internalIneligibilityFactors) {
      this.internalIneligibilityFactors = internalIneligibilityFactors;
   }

   public IneligibilityFactor getIneligibilityFactor() {
      Set ineligibilityFactors = getInternalIneligibilityFactors();
      return ineligibilityFactors.size() > 0 ? (IneligibilityFactor)ineligibilityFactors
            .iterator().next() : null;
   }

   public void setIneligibilityFactor(IneligibilityFactor ineligibilityFactor) {
      Set ineligibilityFactors = getInternalIneligibilityFactors();
      Iterator iter = ineligibilityFactors.iterator();
      if( iter.hasNext() ) {
         IneligibilityFactor o = (IneligibilityFactor)iter.next();
         o.setPerson(null);
      }
      ineligibilityFactors.clear();

      if( ineligibilityFactor != null ) {
         ineligibilityFactors.add(ineligibilityFactor);
         ineligibilityFactor.setPerson(this);
      }
   }

   private Set getInternalIncompetenceRulings() {
      if( internalIncompetenceRulings == null ) {
         this.internalIncompetenceRulings = new HashSet();
      }
      return this.internalIncompetenceRulings;
   }

   private void setInternalIncompetenceRulings(Set internalIncompetenceRulings) {
      this.internalIncompetenceRulings = internalIncompetenceRulings;
   }

   public IncompetenceRuling getIncompetenceRuling() {
      Set rulings = getInternalIncompetenceRulings();
      if( rulings.size() > 0 ) {
         return (IncompetenceRuling)rulings.iterator().next();
      }
      return null;
   }

   public void setIncompetenceRuling(IncompetenceRuling incompetenceRuling) {
      Set rulings = getInternalIncompetenceRulings();
      rulings.clear();
      if( incompetenceRuling != null ) {
         rulings.add(incompetenceRuling);
         incompetenceRuling.setPerson(this);
      }
   }

   private Map getInternalFinancialStatements() {
      if( this.internalFinancialStatements == null ) {
         this.internalFinancialStatements = new HashMap();
      }
      return this.internalFinancialStatements;
   }

   private void setInternalFinancialStatements(Map internalFinancialStatements) {
      this.internalFinancialStatements = internalFinancialStatements;
   }

   /**
    * Unmodifiable
    *
    * @return
    */
   public Map getFinancialStatements() {
      return Collections.unmodifiableMap(getInternalFinancialStatements());
   }

   public FinancialStatement getFinancialStatement(Integer incomeYear) {
      return (FinancialStatement)getInternalFinancialStatements().get(incomeYear);
   }

   /**
    * Set a FinancialStatement for the income year. If the FinancialStatement for the
    * income year is null, remove the income year from the collection of
    * FinancialStatements.
    *
    * @param incomeYear
    * @param financialStatement
    */
   public void setFinancialStatement(Integer incomeYear,
         FinancialStatement financialStatement) {
      setFinancialStatement(incomeYear, financialStatement, false);
   }

   public Integer getLatestIncomeYear() {
		Map stmts = getFinancialStatements();
		Iterator itr = stmts != null ? stmts.keySet().iterator() : null;
		Integer incomeYear = null;

		Integer latestIncomeYear = null;
		// only deal with latest income year (note this will actually be for the previous years financials)
		while(itr != null && itr.hasNext()) {
			incomeYear = (Integer) itr.next();
			if(latestIncomeYear == null) {
				latestIncomeYear = incomeYear;
			}
			else {
				if(incomeYear.intValue() > latestIncomeYear.intValue())
					latestIncomeYear = incomeYear;
			}
		}
		return latestIncomeYear;
   }

   /**
    * Set a FinancialStatement for the income year even if the FinancialStatement is null.
    *
    * @param incomeYear
    * @param financialStatement
    * @param keepNullValue -
    *           if true, set the FinancialStatement for the income year even if it is
    *           null. If false and FinancialStatement is null, remove the income year from
    *           the collection of FinancialStatements
    */
   public void setFinancialStatement(Integer incomeYear,
         FinancialStatement financialStatement, boolean keepNullValue) {
      Validate.notNull(incomeYear, "Income year cannot be null");

      FinancialStatement current = this.getFinancialStatement(incomeYear);
      // If existing financial statement is different from incoming
      if( ( current == null && financialStatement == null )
            || current != financialStatement ) {

         // Remove any existing financial statement for that income year
         if( current != null ) {
            this.getInternalFinancialStatements().remove(incomeYear);
            current.setPerson(null);
         }
         if( financialStatement != null ) {
            getInternalFinancialStatements().put(incomeYear, financialStatement);
            financialStatement.setPerson(this);
            financialStatement.setIncomeYear(incomeYear);
         }
         else {// If financial statement is null && keepNullValue
            if( keepNullValue ) {
               getInternalFinancialStatements().put(incomeYear, null);
            }
         }
      }
   }

   /**
    * Removes the Map containing all FinancialStatements
    */
   public void removeAllFinancialStatements() {
      getInternalFinancialStatements().clear();
   }

   private Map getInternalInProcessFinancials() {
      if( internalInProcessFinancials == null ) {
         internalInProcessFinancials = new HashMap();
      }
      return this.internalInProcessFinancials;
   }

   private Map setInternalInProcessFinancials(Map inProcessFinancials) {
      return this.internalInProcessFinancials = inProcessFinancials;
   }

   public InProcessFinancialInfo getInProcessFinancial(Integer incomeYear) {
      return (InProcessFinancialInfo)getInternalInProcessFinancials().get(incomeYear);
   }

   public void setInProcessFinancial(Integer incomeYear,
         InProcessFinancialInfo inProcessFinancial) {
      Validate.notNull(incomeYear, "Income year cannot be null");

      InProcessFinancialInfo current = getInProcessFinancial(incomeYear);
      if( current != inProcessFinancial ) {
         if( current != null ) {
            this.getInternalInProcessFinancials().remove(incomeYear);
            current.setPerson(null);
         }
         if( inProcessFinancial != null ) {
            getInternalInProcessFinancials().put(incomeYear, inProcessFinancial);
            inProcessFinancial.setPerson(this);
            inProcessFinancial.setIncomeYear(incomeYear);
         }
      }
   }

   public void removeAllInProcessFinancials() {
      getInternalInProcessFinancials().clear();
   }

   private Map getInternalIncomeTests() {
      if( internalIncomeTests == null ) {
         internalIncomeTests = new HashMap();
      }
      return this.internalIncomeTests;
   }

   private Map setInternalIncomeTests(Map incomeTests) {
      return this.internalIncomeTests = incomeTests;
   }

   /**
    * Returns an unmodifiable map of the income years mapped to their IncomeTest.
    *
    * @return The income tests
    */
   public Map getIncomeTests() {
      return Collections.unmodifiableMap(getInternalIncomeTests());
   }

   public IncomeTest getIncomeTest(Integer incomeYear) {
      return (IncomeTest)getInternalIncomeTests().get(incomeYear);
   }

   /**
    * Set a IncomeTest for the income year. If the IncomeTest for the income year is null,
    * remove the income year from the collection of IncomeTests.
    *
    * @param incomeYear
    * @param incomeTest
    */

   public void setIncomeTest(Integer incomeYear, IncomeTest incomeTest) {
      setIncomeTest(incomeYear, incomeTest, false);
   }

   /**
    * Set a IncomeTest for the income year even if the IncomeTest is null.
    *
    * @param incomeYear
    * @param incomeTest
    * @param keepNullValue -
    *           if true, set the IncomeTest for the income year even if it is null. If
    *           false and IncomeTest is null, remove the income year from the collection
    *           of IncomeTests
    */
   public void setIncomeTest(Integer incomeYear, IncomeTest incomeTest,
         boolean keepNullValue) {
      Validate.notNull(incomeYear, "Income year cannot be null");

      IncomeTest current = this.getIncomeTest(incomeYear);
      if( current != incomeTest ) {
         if( current != null ) {
            this.getInternalIncomeTests().remove(incomeYear);
            current.setPerson(null);
         }
         if( incomeTest != null ) {
            getInternalIncomeTests().put(incomeYear, incomeTest);
            incomeTest.setPerson(this);
            Validate.isTrue(incomeYear.equals(incomeTest.getIncomeYear()),
                  "incomeYear should match incomeTest.incomeYear");

         }
         else {// If incomeTest is null && keepNullValue
            if( keepNullValue ) {
               getInternalIncomeTests().put(incomeYear, null);
            }
         }
      }
   }

   /**
    * Removes the Map containing all IncomeTests
    */
   public void removeAllIncomeTests() {
      getInternalIncomeTests().clear();
   }

   public Set getDecorations() {
      return Collections.unmodifiableSet(getInternalDecorations());
   }

   public Decoration getDecorationByEntityKey(EntityKey identifier) {
      return (Decoration)getEntityByEntityKey(getDecorations(), identifier);
   }

   public Decoration removeDecorationByEntityKey(EntityKey identifier) {
      return (Decoration)removeEntityByEntityKey(getInternalDecorations(), identifier);
   }

   public Decoration getDecorationByType(Class type) {
      Set decorations = this.getInternalDecorations();
      Object decoration = type != null ? CollectionUtils.getObjectOfClassType(
            decorations, type) : null;
      return decoration instanceof Decoration ? (Decoration)decoration : null;
   }

   public PurpleHeart getPurpleHeart() {
      Decoration decoration = this.getDecorationByType(PurpleHeart.class);
      return decoration instanceof PurpleHeart ? (PurpleHeart)decoration : null;
   }

   public void setPurpleHeart(PurpleHeart purpleHeart) {
      getInternalDecorations().clear();
      if (purpleHeart != null) {
    	  getInternalDecorations().add(purpleHeart);
    	  purpleHeart.setPerson(this);
      }
   }

   private Set getInternalDecorations() {
      if( this.internalDecorations == null ) {
         this.internalDecorations = new HashSet();
      }
      return this.internalDecorations;
   }

   public void addDecoration(Decoration decoration) {
      Validate.notNull(decoration, "Null Decoration record specified.");
      getInternalDecorations().add(decoration);
      decoration.setPerson(this);
   }

   public void removeDecoration(Decoration decoration) {
      Validate.notNull(decoration, "Null Decoration record specified.");
      getInternalDecorations().remove(decoration);
      decoration.setPerson(null);
   }

   private void setInternalDecorations(Set decorations) {
      this.internalDecorations = decorations;
   }

   public void removeAllDecorations() {
      this.getInternalDecorations().clear();
   }

   public MedalOfHonor getMedalOfHonor() {
	   Set honors = this.getInternalMedalOfHonors();
	   if( honors.size() > 0 ) {
		   return (MedalOfHonor)honors.iterator().next();
	   }
	   return null;
   }

   public void setMedalOfHonor(MedalOfHonor medalOfHonor) {
	   getInternalMedalOfHonors().clear();
	   // Make sure medalOfHonor is not null
	   if (medalOfHonor != null) {
		   getInternalMedalOfHonors().add(medalOfHonor);
		   medalOfHonor.setPerson(this);
	   }
   }

   public void removeAllMedalOfHonors() {
	   this.getInternalMedalOfHonors().clear();
   }

   private Set getInternalMedalOfHonors() {
	   if( this.internalMedalOfHonors == null ) {
		   this.internalMedalOfHonors = new HashSet();
	   }
	   return this.internalMedalOfHonors;
   }

   private void setInternalMedalOfHonors(Set internalMedalOfHonors) {
	this.internalMedalOfHonors = internalMedalOfHonors;
   }

public SHAD getShad() {
      Set shads = getInternalShads();
      return shads.size() > 0 ? (SHAD)shads.iterator().next() : null;
   }

   public void setShad(SHAD shad) {
      Set shads = getInternalShads();
      Iterator iter = shads.iterator();
      if( iter.hasNext() ) {
         SHAD o = (SHAD)iter.next();
         o.setPerson(null);
      }
      shads.clear();

      if( shad != null ) {
         shads.add(shad);
         shad.setPerson(this);
      }
   }

   private Set getInternalShads() {
      if( this.internalShads == null ) {
         this.internalShads = new HashSet();
      }
      return this.internalShads;
   }

   private void setInternalShads(Set shads) {
      this.internalShads = shads;
   }

   private Set getInternalMonetaryBenefitAwards() {
      if( internalMonetaryBenefitAwards == null ) {
         this.internalMonetaryBenefitAwards = new HashSet();
      }
      return this.internalMonetaryBenefitAwards;
   }

   private void setInternalMonetaryBenefitAwards(Set internalMonetaryBenefitAwards) {
      this.internalMonetaryBenefitAwards = internalMonetaryBenefitAwards;
   }

   public MonetaryBenefitAward getMonetaryBenefitAward() {
      Set awards = getInternalMonetaryBenefitAwards();
      if( awards.size() > 0 ) {
         return (MonetaryBenefitAward)awards.iterator().next();
      }
      return null;
   }

   public void setMonetaryBenefitAward(MonetaryBenefitAward monetaryBenefitAward) {
      Set awards = getInternalMonetaryBenefitAwards();
      awards.clear();
      if( monetaryBenefitAward != null ) {
         awards.add(monetaryBenefitAward);
         monetaryBenefitAward.setPerson(this);
      }
   }

   public MilitaryService getMilitaryService() {
	   if (this.militaryService == null) {
		   this.militaryService = new MilitaryService();
		   this.militaryService.setPerson(this);

	   }
      return this.militaryService;
    }

   public Set getMilitaryServiceNumbers() {
      Set nums = new HashSet();
      MilitaryServiceEpisode ep = null;
      if( getMilitaryService() != null ) {
         Set siteRecords = getMilitaryService().getMilitaryServiceSiteRecords();
         if( siteRecords != null ) {
            Iterator itr = siteRecords.iterator();
            MilitaryServiceSiteRecord siteRec = null;
            while( itr.hasNext() ) {
               siteRec = (MilitaryServiceSiteRecord)itr.next();
               Set eps = siteRec.getMilitaryServiceEpisodes();
               if( eps != null ) {
                  Iterator itr2 = eps.iterator();
                  while( itr2.hasNext() ) {
                     ep = (MilitaryServiceEpisode)itr2.next();
                     if( ep.getServiceNumber() != null )
                        nums.add(ep.getServiceNumber());
                  }
               }
            }
         }
      }
      return nums;
   }

   public void setMilitaryService(MilitaryService militaryService) {
      if( this.militaryService != militaryService ) {
         if( this.militaryService != null ) {
            this.militaryService.setPerson(null);
         }
         if( militaryService != null ) {
            militaryService.setPerson(this);
         }
         this.militaryService = militaryService;
      }
   }

   public VAFacility getMostRecentPreferredFacility() {
      return this.mostRecentPreferredFacility;
   }

   public void setMostRecentPreferredFacility(VAFacility mostRecentPreferredFacility) {
      this.mostRecentPreferredFacility = mostRecentPreferredFacility;
   }

   public BirthRecord getBirthRecord() {
      return this.birthRecord;
   }

   public void setBirthRecord(BirthRecord birthRecord) {
      this.birthRecord = birthRecord;
   }

   public DeathRecord getDeathRecord() {
      return this.deathRecord;
   }

   public void setDeathRecord(DeathRecord deathRecord) {
      this.deathRecord = deathRecord;
   }

   public boolean isDeceased() {
      return ( deathRecord != null && deathRecord.getDeathDate() != null );
   }

   private Set getInternalCancelDeclines() {
      if( internalCancelDeclines == null ) {
         this.internalCancelDeclines = new HashSet();
      }
      return this.internalCancelDeclines;
   }

   private void setInternalCancelDeclines(Set internalCancelDeclines) {
      this.internalCancelDeclines = internalCancelDeclines;
   }

   public CancelDecline getCancelDecline() {
      Set declines = getInternalCancelDeclines();
      if( declines.size() > 0 ) {
         return (CancelDecline)declines.iterator().next();
      }
      return null;
   }

   public void setCancelDecline(CancelDecline cancelDecline) {
      Set declines = getInternalCancelDeclines();
      declines.clear();
      if( cancelDecline != null ) {
         declines.add(cancelDecline);
         cancelDecline.setPerson(this);
      }
   }

   private Set getInternalApplications() {
      if( internalApplications == null ) {
         this.internalApplications = new HashSet();
      }
      return this.internalApplications;
   }

   private void setInternalApplications(Set internalApplications) {
      this.internalApplications = internalApplications;
   }

   public Application getApplication() {
      Set applications = getInternalApplications();
      return applications.size() > 0 ? (Application)applications.iterator().next() : null;
   }

   public void setApplication(Application application) {
      Set applications = getInternalApplications();
      Iterator iter = applications.iterator();
      if( iter.hasNext() ) {
         Application o = (Application)iter.next();
         applications.remove(o);
         o.setPerson(null);
      }
      if( application != null ) {
         applications.add(application);
         application.setPerson(this);
      }
   }

   private Set getInternalMedicaidFactors() {
      if( internalMedicaidFactors == null ) {
         this.internalMedicaidFactors = new HashSet();
      }
      return this.internalMedicaidFactors;
   }

   private void setInternalMedicaidFactors(Set internalMedicaidFactors) {
      this.internalMedicaidFactors = internalMedicaidFactors;
   }

   public MedicaidFactor getMedicaidFactor() {
      Set factors = getInternalMedicaidFactors();
      if( factors.size() > 0 ) {
         return (MedicaidFactor)factors.iterator().next();
      }
      return null;
   }

   public void setMedicaidFactor(MedicaidFactor medicaidFactor) {
      Set factors = getInternalMedicaidFactors();
      factors.clear();
      if( medicaidFactor != null ) {
         factors.add(medicaidFactor);
         medicaidFactor.setPerson(this);
      }
   }

   private Set getInternalPreferredLanguages() {
       if( internalPreferredLanguages == null ) {
          this.internalPreferredLanguages = new HashSet();
       }
       return this.internalPreferredLanguages;
    }

    private void setInternalPreferredLanguages(Set internalPreferredLanguages) {
       this.internalPreferredLanguages = internalPreferredLanguages;
    }

    public PreferredLanguage getPreferredLanguage() {
        Set languages = getInternalPreferredLanguages();
        if( languages.size() > 0 ) {
           return (PreferredLanguage)languages.iterator().next();
        }
        return null;
     }

     public void setPreferredLanguage(PreferredLanguage preferredLanguage) {
        Set languages = getInternalPreferredLanguages();
        languages.clear();
        if( preferredLanguage != null ) {
           languages.add(preferredLanguage);
           preferredLanguage.setPerson(this);
        }
     }


   /**
    * Getter - For hibernate use only
    *
    * @return
    */
   private Set getInternalEligibilityVerifications() {
      if( this.internalEligibilityVerifications == null ) {
         this.internalEligibilityVerifications = new HashSet();
      }
      return this.internalEligibilityVerifications;
   }

   /**
    * Setter - For hibernate use only
    *
    * @param internalEligibilityVerifications
    */
   private void setInternalEligibilityVerifications(Set internalEligibilityVerifications) {
      this.internalEligibilityVerifications = internalEligibilityVerifications;
   }

   /**
    * Get the EligibilityVerification of this person.
    *
    * @return EligibilityVerification or null if no eligibility verification exists for
    *         this person.
    */
   public EligibilityVerification getEligibilityVerification() {
      Set verifications = getInternalEligibilityVerifications();
      if( verifications.size() > 0 ) {
         return (EligibilityVerification)this.internalEligibilityVerifications.iterator()
               .next();
      }
      return null;
   }

   /**
    * Set the EligibilityVerification of this person.
    *
    * @param eligibilityVerification
    */
   public void setEligibilityVerification(EligibilityVerification eligibilityVerification) {
      Set verifications = getInternalEligibilityVerifications();
      verifications.clear();
      if( eligibilityVerification != null ) {
         getInternalEligibilityVerifications().add(eligibilityVerification);
         eligibilityVerification.setPerson(this);
      }
   }

   private Set getInternalEnrollmentDeterminations() {
      if( internalEnrollmentDeterminations == null ) {
         this.internalEnrollmentDeterminations = new HashSet();
      }
      return this.internalEnrollmentDeterminations;
   }

   private void setInternalEnrollmentDeterminations(Set internalEnrollmentDeterminations) {
      this.internalEnrollmentDeterminations = internalEnrollmentDeterminations;
   }

   public Set getEnrollmentDeterminations(){
       return this.internalEnrollmentDeterminations;
   }

   public EnrollmentDetermination getEnrollmentDetermination() {
      Set determinations = getInternalEnrollmentDeterminations();
      if( determinations.size() == 1 ) {
         return (EnrollmentDetermination)determinations.iterator().next();
      }
      // FIXME Currently history of multiple enrollment records are retrieved.
      // Only one is valid, which is
      // the one with the largest enrollment_determination id
      // This is a workaround to pick the correct one. This should have been
      // filtered at the history dao level,
      // remove this code after history dao has been updated.
      else if( determinations.size() > 1 ) {
         EnrollmentDetermination enrollment = null;
         Iterator iter = determinations.iterator();
         while( iter.hasNext() ) {
            EnrollmentDetermination e = (EnrollmentDetermination)iter.next();
            if( enrollment == null ) {
               enrollment = e;
            }
            else if( ( e != null )
                  && ( e.getEntityKey() != null )
                  && ( enrollment.getEntityKey() != null )
                  && ( e.getEntityKey().getKeyValue() != null )
                  && ( enrollment.getEntityKey().getKeyValue() != null )
                  && ( ( (BigDecimal)e.getEntityKey().getKeyValue() )
                        .compareTo((BigDecimal)enrollment.getEntityKey().getKeyValue()) > 0 ) ) {
               enrollment = e;
            }
         }
         return enrollment;
      }
      return null;
   }

   public void setEnrollmentDetermination(EnrollmentDetermination enrollmentDetermination) {
      Set determinations = getInternalEnrollmentDeterminations();
      determinations.clear();
      if( enrollmentDetermination != null ) {
         determinations.add(enrollmentDetermination);
         enrollmentDetermination.setPerson(this);
         setMigratedEE(); // since ESR calculated an EnrollmentDetermination, it is defacto migrated
      }
   }

   public void setMigratedEE() {
       // make sure this is flipped (but if null, ignore)
       if( Boolean.FALSE.equals(getMigratedEE()) ) {
          setMigratedEE(Boolean.TRUE);
       }
   }

   public Integer getUserEnrolleeValidThrough() {
      return this.userEnrolleeValidThrough;
   }

   public void setUserEnrolleeValidThrough(Integer userEnrolleeValidThrough) {
      this.userEnrolleeValidThrough = userEnrolleeValidThrough;
   }

   public VAFacility getUserEnrolleeSite() {
      return this.userEnrolleeSite;
   }

   public void setUserEnrolleeSite(VAFacility userEnrolleeSite) {
      this.userEnrolleeSite = userEnrolleeSite;
   }

   /**
    * @return Returns the sensitiveRecord.
    */
   public Boolean getSensitiveRecord() {
      return sensitiveRecord;
   }

   /**
    * @return Returns the sensitiveRecord.
    */
   public Boolean isSensitiveRecord() {
      return sensitiveRecord;
   }

   /**
    * @param sensitiveRecord
    *           The sensitiveRecord to set.
    */
   public void setSensitiveRecord(Boolean sensitiveRecord) {
      this.sensitiveRecord = sensitiveRecord;
   }

   /**
    * @return Returns the sensitiveRecord.
    */
   public boolean isPersonLocked() {
      return getPersonLockedReason() != null;
   }

   public PersonLockedReason getPersonLockedReason() {
      return personLockedReason;
   }

   public void setPersonLockedReason(PersonLockedReason personLockedReason) {
      this.personLockedReason = personLockedReason;
   }

   public Date getSensitivityChangeDate() {
      return this.sensitivityChangeDate;
   }

   public void setSensitivityChangeDate(Date sensitivityChangeDate) {
      this.sensitivityChangeDate = sensitivityChangeDate;
   }

   public SensitivityChangeSource getSensitivityChangeSource() {
      return this.sensitivityChangeSource;
   }

   public void setSensitivityChangeSource(SensitivityChangeSource sensitivityChangeSource) {
      this.sensitivityChangeSource = sensitivityChangeSource;
   }

   public VAFacility getSensitivityChangeSite() {
      return this.sensitivityChangeSite;
   }

   public void setSensitivityChangeSite(VAFacility sensitivityChangeSite) {
      this.sensitivityChangeSite = sensitivityChangeSite;
   }

   /**
    * Indicate if the person is a veteran
    *
    * @return
    */
   public Boolean isVeteran() {
      return getVeteran();
   }

   /**
    * Indicate if the person is a veteran. For hibernate mapping
    *
    * @return
    */
   public Boolean getVeteran() {
      return this.veteran;
   }

   /**
    * Set if the person is a veteran
    *
    * @param veteran
    *           true if the person is a veteran
    */
   public void setVeteran(Boolean veteran) {
      this.veteran = veteran;
   }

   public String getClaimFolderNumber() {
      return this.claimFolderNumber;
   }

   public void setClaimFolderNumber(String claimFolderNumber) {
      this.claimFolderNumber = claimFolderNumber;
   }

   public String getMailStopReason() {
	return mailStopReason;
   }

	public void setMailStopReason(String mailStopReason) {
		this.mailStopReason = mailStopReason;
	}

public VAFacility getClaimFolderLocation() {
      return this.claimFolderLocation;
   }

   public void setClaimFolderLocation(VAFacility claimFolderLocation) {
      this.claimFolderLocation = claimFolderLocation;
   }

   private Set getInternalEnrollmentOverrides() {
      if( internalEnrollmentOverrides == null ) {
         this.internalEnrollmentOverrides = new HashSet();
      }
      return this.internalEnrollmentOverrides;
   }

   private void setInternalEnrollmentOverrides(Set internalEnrollmentOverrides) {
      this.internalEnrollmentOverrides = internalEnrollmentOverrides;
   }

   public EnrollmentOverride getEnrollmentOverride() {
      Set overrides = getInternalEnrollmentOverrides();
      return overrides.size() > 0 ? (EnrollmentOverride)overrides.iterator().next()
            : null;
   }

   public void setEnrollmentOverride(EnrollmentOverride enrollmentOverride) {
      Set overrides = getInternalEnrollmentOverrides();
      Iterator iter = overrides.iterator();
      if( iter.hasNext() ) {
         EnrollmentOverride o = (EnrollmentOverride)iter.next();
         overrides.remove(o);
         o.setPerson(null);
      }
      if( enrollmentOverride != null ) {
         overrides.add(enrollmentOverride);
         enrollmentOverride.setPerson(this);
      }
   }

   /**
    * @return A collection of SignatureImage object
    */
   public Set getSignatureImages() {
      return Collections.unmodifiableSet(getInternalSignatureImages());
   }

   /**
    * Return the SignatureImage for a given year.
    *
    * @param year
    * @return
    */
   public SignatureImage getSignatureImage(Integer year) {
      Validate.notNull(year, "Income year can not be null.");
      for( Iterator iter = getInternalSignatureImages().iterator(); iter.hasNext(); ) {
         SignatureImage sigImg = (SignatureImage)iter.next();
         if( year.equals(sigImg.getIncomeYear()) ) {
            return sigImg;
         }
      }
      return null;
   }

   public SignatureImage getSignatureImageByEntityKey(EntityKey identifier) {
      return (SignatureImage)getEntityByEntityKey(getSignatureImages(), identifier);
   }

   public SignatureImage removeSignatureImageByEntityKey(EntityKey identifier) {
      return (SignatureImage)removeEntityByEntityKey(getInternalSignatureImages(),
            identifier);
   }

   private Set getInternalSignatureImages() {
      if( this.internalSignatureImages == null ) {
         this.internalSignatureImages = new HashSet();
      }
      return this.internalSignatureImages;
   }

   /**
    * Setter - for hibernate use only.
    */
   private void setInternalSignatureImages(Set signatureImages) {
      this.internalSignatureImages = signatureImages;
   }

   public void addSignatureImage(SignatureImage signatureImage) {
      Validate.notNull(signatureImage, "Null signature image specified.");
      signatureImage.setPerson(this);
      getInternalSignatureImages().add(signatureImage);
   }

   public void addAllSignatureImages(Set signatureImages) {
      Validate.notNull(signatureImages, "Null set of signature images specified.");
      this.setOwner(signatureImages);
      Set internal = this.getInternalSignatureImages();
      internal.addAll(signatureImages);
   }

   /**
    * Remove a Signature image for this person.
    */
   public void removeSignatureImage(SignatureImage signatureImage) {
      Validate.notNull(signatureImage, "Null signatureImage specified.");
      getInternalSignatureImages().remove(signatureImage);
   }

   public void removeAllSignatureImages() {
      this.getInternalSignatureImages().clear();
   }

   /**
    * @return Returns the vpid.
    */
   public VPIDEntityKey getVPIDEntityKey() {
      return ( vpidValue != null ) ? CommonEntityKeyFactory
            .createVPIDEntityKey(vpidValue) : null;
   }

   private Set createDecoratedSet(Set internalSet, Class type, Transformer transformer,
         Transformer removeTransformer) {
      Predicate predicate = AndPredicate.getInstance(NotNullPredicate.getInstance(),
            InstanceofPredicate.getInstance(type));
      Transformer predicatedTransformer = PredicatedTransformer.getInstance(transformer,
            predicate);
      Set decorate = TransformedSet.decorate(internalSet, predicatedTransformer);
      return RemoveTransformedSet.decorate(decorate, removeTransformer);
   }

   public boolean hasPendingUpdatesToIdentityTraits() {
      return pendingUpdatesForIdentityTraits != null;
   }

   // private since the ESR application should never call these (except for
   // testing) - still needed by Hibernate though
	/** Do not call this method.  It is for use by XML Serialization only. */
  /**
    * @return Returns the vpid.
    */
   public String getVPIDValue() {
      return vpidValue;
   }

   /**
    * @param vpidValue
    *           The vpid to set.
    */
   public void setVPIDValue(String vpidValue) {
      this.vpidValue = vpidValue;
   }

   /**
    * @return Returns the edipi.
    */
   public String getEdipi() {
	return edipi;
   }

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


   /**
    * @return Returns the vpid.
    */
   private PersonVPID getVPID() {
      return vpid;
   }

   /**
    * @param vpid
    *           The vpid to set.
    */
   public void setVPID(PersonVPID vpid) {
      this.vpid = vpid;
   }

   private void setOwner(AbstractKeyedEntity entity) {
      Validate.notNull(entity, "Null entity specified");
      try {
         // Invoke a setPerson method on an entity to set
         // this (Person) into it. VL
         Reflector.invoke(entity, "setPerson", new Object[] { this });
      }
      catch( Exception e ) {
         // Catch all exception here since there is reason to handle each
         // exception separately - VL
         if( getLogger().isDebugEnabled() ) {
            getLogger().debug("Failed to set person as an owner for entity " + entity, e);
         }
      }
   }

   private void setOwner(Collection entities) {

      // JDK 5.0, we can pass in a collection of the same type
      // For now, we enfore that a collection must contain
      // only elements of type AbstractKeyedEntity - VL

      Validate.notNull(entities, "Null entity specified");
      for( Iterator i = entities.iterator(); i.hasNext(); ) {
         Object entity = i.next();
         // This will throw a ClassCastException to
         // let a caller handle properly since a collection
         // must contain only AbstractKeyedEntity - VL
         this.setOwner((AbstractKeyedEntity)entity);
      }
   }

   /*
    * (non-Javadoc)
    *
    * @see gov.va.med.fw.model.AbstractKeyedEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
    */
   protected void buildToString(ToStringBuilder builder) {
      builder.append("appointmentRequestDate", this.appointmentRequestDate);
      builder.append("appointmentRequestResponse", this.appointmentRequestResponse);
      builder.append("gender", this.gender);
      builder.append("selfIdentifiedGender", this.selfIdentifiedGenderIdentity);
      builder.append("degree", this.degree);
      builder.append("maritalStatus", this.maritalStatus);
      // builder.append("vpid", this.vpid);
      builder.append("vpidValue", this.vpidValue);
      builder.append("names", this.internalNames);
      builder.append("internalAssociations", this.internalAssociations);
      builder.append("internalInsurances", this.internalInsurances);
      builder.append("internalPreferredLanguages", this.internalPreferredLanguages);
      builder.append("birthRecord", this.birthRecord);
      builder.append("deathRecord", this.deathRecord);
       builder.append("medicaidFactor", this.internalMedicaidFactors);
      builder.append("patientSensitivity", this.sensitiveRecord);
      builder.append("patientSensitivityChangeDate", this.sensitivityChangeDate);
      builder.append("patientSensitivityChangeSource", this.sensitivityChangeSource);
      builder.append("patientSensitivityChangeSite", this.sensitivityChangeSite);
      builder.append("userEnrolleeValidThrough", this.userEnrolleeValidThrough);
      builder.append("internalEligibilityVerifications",
            this.internalEligibilityVerifications);
      builder.append("veteran", this.veteran);
      builder.append("specialFactors", this.internalSpecialFactors);
      builder.append("militaryService", this.militaryService);
      builder.append("religion", this.religion);
      builder.append("VOAIndicator", this.VOAIndicator);
      //builder.append("SSNs", this.getSsns());
      builder.append("idmMatchType", this.idmMatchType);

      super.buildToString(builder);
   }

   /**
    * @return Returns the pendingUpdatesForIdentityTraits.
    */
   public PersonIdentityTraits getPendingUpdatesForIdentityTraits() {
      return pendingUpdatesForIdentityTraits;
   }

   /**
    * @param pendingUpdatesForIdentityTraits
    *           The pendingUpdatesForIdentityTraits to set.
    */
   public void setPendingUpdatesForIdentityTraits(
         PersonIdentityTraits pendingUpdatesForIdentityTraits) {
      this.pendingUpdatesForIdentityTraits = pendingUpdatesForIdentityTraits;
   }

   /**
    * Extracts the identity traits from the Person and returns them as a
    * PersonIdentityTraits object.
    *
    * @return The PersonIdentityTraits object.
    */
   public PersonIdentityTraits getIdentityTraits() {
      PersonIdentityTraits traits = new PersonIdentityTraits();
      traits.setGender(getGender());
      traits.setNames(getNames());
      traits.setMothersMaidenName(this.mothersMaidenName);
      //traits.setSigi(this.getSelfIdentifiedGenderIdentity());

      /*
       * hierarchy here... Currently, all SSN's are stored by PSIM. In addition, they only
       * store ONE SSN (even though ESR Person object has always supported more than one
       * SSN). So the below logic is based on that. In the future, it has been discussed
       * that PSIM will support more than one SSN per Person. When that happens, this
       * logic needs to be revisisted.
       */
      SSN ssnOfficial = getOfficialSsn();
      if( ssnOfficial != null ) {
         traits.setSsn(ssnOfficial);
      }
      else {
        Set ssnOther = getOtherSsns();
        if( ssnOther != null && !ssnOther.isEmpty() )
           traits.setSsn((SSN)ssnOther.iterator().next());
      }

      traits.setBirthRecord(getBirthRecord());
      traits.setVpid(getVPIDEntityKey());
      
      // CR 13726
      traits.setEdipi(getEdipi());

      // get the locked reason
      PersonLockedReason plr = getPersonLockedReason();
      if( plr != null ) {
         if( PersonLockedReason.PENDING_IDENTITY_TRAIT_UPDATES.equals(plr.getReason()) )
            traits.setHasPendingUpdates(true);
         else if( PersonLockedReason.PERSON_DEPRECATED.equals(plr.getReason()) )
            traits.setDeprecated(true);
      }
      return traits;
   }

   /**
    * Copies data from PersonIdentityTraits object onto the appropriate Person attributes.
    * Nothing will be done if no trait data is passed in.
    *
    * @param traits
    *           The traits to set.
    */
   public void setIdentityTraits(PersonIdentityTraits traits) {
      // Check if any trait data is present
      if( traits == null ) {
         return;
      }

      // Since the only names should be coming from PSIM, clear them out first
      removeAllNames();

      // Add the names
      Iterator itr = traits.getNames() != null ? traits.getNames().iterator() : null;
      while( itr != null && itr.hasNext() ) {
         addName((Name)itr.next());
      }
      this.mothersMaidenName = traits.getMothersMaidenName();
      //this.selfIdentifiedGenderIdentity = traits.getSigi();

      // Add the birth record
      setBirthRecord(traits.getBirthRecord());

      // PSIM owns all the SSN's...clear out and use what it has...
      removeAllSsns();
      SSN psimSSN = traits.getSsn();
      if( psimSSN != null )
         addSsn(psimSSN);

      // Set the gender
      setGender(traits.getGender());

      // CR 13726
      this.setEdipi(traits.getEdipi());

      this.identityTraitsAuditInfo = traits.getAuditInfo();
      // CCR 12665
      setSiteIdentities(traits.getSiteIdentities());
      /* Assumption here is that VPID is already set on Person since that also implies
       * keeping in sync a PersonVPID object
       */
   }

   /**
    * Return list of facilities from FeeBasis and PatientVisitSummary info
    *
    * @return
    */
   public Set getFacilities() {
      Set facilities = new HashSet();
      // Add facilities from Patient Visit Summaries
      Set keySet = getPatientVisitSummaries().keySet();
      for( Iterator i = keySet.iterator(); i.hasNext(); ) {
         facilities.add(( (SiteYear)i.next() ).getFacility());
      }
      // Add facilities from Feebasis info
      for (Iterator i= getInternalFeeBasis().iterator(); i.hasNext();){
          FeeBasis feeBasis = (FeeBasis) i.next();
          facilities.add(feeBasis.getReportSite());
      }
      return facilities;
   }

   /**
    * Set of methods added to support person merge conversion service
    *
    * @return
    */
   // public SHAD getShad() {
   // return (SHAD) getSpecialFactorByType(SHAD.class);
   // }
   public AgentOrangeExposure getAgentOrangeExposure() {
      return (AgentOrangeExposure)getSpecialFactorByType(AgentOrangeExposure.class);
   }

   public RadiationExposure getRadiationExposure() {
      return (RadiationExposure)getSpecialFactorByType(RadiationExposure.class);
   }

   public EnvironmentalContaminationExposure getEnvironmentalContaminationExposure() {
      return (EnvironmentalContaminationExposure)getSpecialFactorByType(EnvironmentalContaminationExposure.class);
   }
   //////CLV//////////////////////////////
   public CampLejeuneVerification getCampLejeuneVerification(){

	   return (CampLejeuneVerification)getSpecialFactorByType(CampLejeuneVerification.class);
   }
   public void setCampLejeuneVerification(CampLejeuneVerification campLejeuneVerification) {
	      if( campLejeuneVerification == null )
	         removeSpecialFactorByType(CampLejeuneVerification.class);
	      else
	         removeAndAddSpecialFactor(campLejeuneVerification);
	   }
    //////CLV//////////////////////////////

   // public void setShad(SHAD sHAD) {
   // if (sHAD == null)
   // removeSpecialFactorByType(SHAD.class);
   // else
   // removeAndAddSpecialFactor(sHAD);
   // }

   public void setAgentOrangeExposure(AgentOrangeExposure agentOrangeExposure) {
      if( agentOrangeExposure == null )
         removeSpecialFactorByType(AgentOrangeExposure.class);
      else
         removeAndAddSpecialFactor(agentOrangeExposure);
   }

   public void setRadiationExposure(RadiationExposure radiationExposure) {
      if( radiationExposure == null )
         removeSpecialFactorByType(RadiationExposure.class);
      else
         removeAndAddSpecialFactor(radiationExposure);
   }

   public void setEnvironmentalContaminationExposure(
         EnvironmentalContaminationExposure environmentalContaminationExposure) {
      if( environmentalContaminationExposure == null )
         removeSpecialFactorByType(EnvironmentalContaminationExposure.class);
      else
         removeAndAddSpecialFactor(environmentalContaminationExposure);
   }

   private void removeAndAddSpecialFactor(SpecialFactor specialFactor) {
      SpecialFactor old = getSpecialFactorByType(specialFactor.getClass());
      if( old == null ) {
         addSpecialFactor(specialFactor);
      }
      else if( old != specialFactor ) {
         removeSpecialFactor(old);
         addSpecialFactor(specialFactor);
      }
   }

   public int getOpenCasesCount() {
      return openCasesCount;
   }

   public void setOpenCasesCount(int openCases) {
      this.openCasesCount = openCases;
   }

   /**
    * @return Returns the migratedEE.
    */
   public Boolean getMigratedEE() {
      return migratedEE;
   }

   /**
    * @param migratedEE
    *           The migratedEE to set.
    */
   public void setMigratedEE(Boolean migratedEE) {
      this.migratedEE = migratedEE;
   }

   /**
    * Returns an instance of sendingFacility
    * @return String sendingFacility.
    */
   public String getSendingFacility() {
      return sendingFacility;
   }

   /**
    * Sets the sendingFacility of type String
    * @param sendingFacility The sendingFacility to set.
    */
   public void setSendingFacility(String sendingFacility) {
      this.sendingFacility = sendingFacility;
   }

    /**
     * Returns whether this person is enrolled or not.
     * @return True if enrolled or false if not.
     */
    public boolean isEnrolled()
    {
        return getEnrollmentDetermination() != null;
    }

	/**
	 * @return Returns the identityTraitsAuditInfo.
	 */
	public AuditInfo getIdentityTraitsAuditInfo() {
		return identityTraitsAuditInfo;
	}

	/**
	 * @return Returns the mothersMaidenName.
	 */
	public String getMothersMaidenName() {
		return mothersMaidenName;
	}

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

    public void setIdentifier(Serializable identifier) {
        // TODO Auto-generated method stub
        super.setIdentifier(identifier);
    }

    public Employment getEmployment() {
        Set employments = getInternalEmployments();
        return employments.size() > 0 ? (Employment)employments.iterator().next() : null;
    }

    public void setEmployment(Employment employment) {
        Set employments = getInternalEmployments();
        Iterator iter = employments.iterator();
        if (iter.hasNext()) {
            Employment e = (Employment) iter.next();
            employments.remove(e);
            e.setPerson(null);
        }

        if (employment != null) {
            employments.add(employment);
            employment.setPerson(this);
        }
    }

    public void removeEmployment(Employment employment) {
        Validate.notNull(employment, "Employment cannot be null");
        this.getInternalEmployments().remove(employment);
    }

    private Set getInternalEmployments() {
        if (this.internalEmployments == null) {
            this.internalEmployments = new HashSet();
        }
        return this.internalEmployments;
    }

    private void setInternalEmployments(Set employments) {
        this.internalEmployments = employments;
    }

    private Set getInternalRaces() {
        if (this.internalRaces == null) {
            this.internalRaces = new HashSet();
        }
        return this.internalRaces;
    }

    private void setInternalRaces(Set internalRaces) {
        this.internalRaces = internalRaces;
    }

    public Set getRaces() {
        return Collections.unmodifiableSet(getInternalRaces());
    }

    public void addRace(Race race) {
        Validate.notNull(race, "Null Race specified");
        Validate.notNull(race.getRaceType(), "Null RaceType specified");
        Race existingRace = getRaceByType(race.getRaceType());
        if( existingRace != null )
           return;
        getInternalRaces().add(race);
        race.setPerson(this);
    }

    public void removeRace(Race race) {
        Validate.notNull(race, "Race cannot be null");
        this.getInternalRaces().remove(race);
    }

    public void removeAllRaces() {
        this.getInternalRaces().clear();
    }

    public Race getRaceByType(RaceType type) {
         Validate.notNull(type, "Null RaceType specified");
         Iterator iter = this.getInternalRaces().iterator();
         while( iter.hasNext() ) {
            Race race = (Race)iter.next();
            if( type.getCode().equals(race.getRaceType().getCode()) )
               return race;
         }
         return null;
    }

    public Ethnicity getEthnicity() {
        Set ethnicities = getInternalEthnicities();
        return ethnicities.size() > 0 ? (Ethnicity) ethnicities.iterator()
                .next() : null;
    }

    public void setEthnicity(Ethnicity ethnicity) {
        Set ethnicities = getInternalEthnicities();
        Iterator iter = ethnicities.iterator();
        if (iter.hasNext()) {
            Ethnicity e = (Ethnicity) iter.next();
            e.setPerson(null);
        }
        ethnicities.clear();

        if (ethnicity != null) {
            ethnicities.add(ethnicity);
            ethnicity.setPerson(this);
        }
    }

    private Set getInternalEthnicities() {
        if (this.internalEthnicities == null) {
            this.internalEthnicities = new HashSet();
        }
        return this.internalEthnicities;
    }

    private void setInternalEthnicities(Set ethnicities) {
        this.internalEthnicities = ethnicities;
    }

    public Religion getReligion() {
        return this.religion;
    }

    public void setReligion(Religion religion) {
        this.religion = religion;
    }

    private Set getInternalRelations() {
        if( internalRelations == null ) {
            internalRelations = new HashSet();
        }
        return this.internalRelations;
     }

     private Set setInternalRelations(Set internalRelations) {
        return this.internalRelations = internalRelations;
     }

     /**
      * Returns an unmodifiable set of the Relations.
      *
      * @return The relations
      */
     public Set getRelations() {
        return Collections.unmodifiableSet(getInternalRelations());
     }

     public Relation getRelationByEntityKey(EntityKey identifier) {
         return (Relation)getEntityByEntityKey(getRelations(), identifier);
      }

      public Relation removeRelationByEntityKey(EntityKey identifier) {
         return (Relation)removeEntityByEntityKey(getInternalRelations(), identifier);
      }

     public Relation getMother() {
         return getRelation(Relationship.CODE_MOTHER.getCode());
     }

     public Relation getFather() {
         return getRelation(Relationship.CODE_FATHER.getCode());
     }

     public void setMother(Relation relation) {
         setRelation(Relationship.CODE_MOTHER.getCode(), relation);
     }

     public void setFather(Relation relation) {
         setRelation(Relationship.CODE_FATHER.getCode(), relation);
     }

     /**
      * Helper method to get the Relation of a given type code. This method iterates the collection of relations
      * and return the Relation of give type code or null if no relation for a given type code exists.
      * This is used for person's mother & father records (not spouse and dependent records, as those are tied
      * to financial statements by year.
      *
      * @param relationshipcode
       *
      * @return the relation of the specified type.
      */
    public Relation getRelation(String relationshipCode) {

        Validate.notNull(relationshipCode, "RelationshipCode must not be null");
        Validate.isTrue((relationshipCode==Relationship.CODE_MOTHER.getCode() || relationshipCode==Relationship.CODE_FATHER.getCode()),
            "This method only applies to Mother and Father");

        if (this.getInternalRelations() == null)
            return null;

        for (Iterator iter = getInternalRelations().iterator(); iter.hasNext();) {
            Relation relation = (Relation) iter.next();
            Relationship relationType = relation.getRelationship();
            if (relationType != null
                    && relationType.getCode().equals(relationshipCode)) {
                return relation;
            }
       }

        return null;
    }

    /**
      * Set a relation based for a particular relationship (type)
      * @param relationshipCode  Type of relation
      * @param relation
      */
     public void setRelation(String relationshipCode, Relation relation) {

       Validate.notNull(relation, "relation cannot be null");

       Validate.notNull(relationshipCode, "relationshipCode cannot be null");
       Validate.isTrue(relationshipCode.equals(Relationship.CODE_MOTHER.getCode()) ||
                relationshipCode.equals(Relationship.CODE_FATHER.getCode()),
        "This method only applies to Mother and Father");

        Relation current = this.getRelation(relationshipCode);
        if( current != relation ) {
           if( current != null ) {
              this.getInternalRelations().remove(current);
              current.setPerson(null);
           }
           if( relation != null ) {
              Validate.isTrue(relation.getRelationship() != null && relationshipCode.equals(relation.getRelationship().getCode()),
                    "relationshipCode should match relation.relationship code");
              addRelation(relation);
           }
         }
     }

     /**
      * Add an Relation for this person. This method takes care of Bidirectional setting
      * of Relation's person.  For now should only be used for mother's name and father's name
      *
      * @param relation
      */
     public void addRelation(Relation relation) {
        Validate.notNull(relation, "Null relation specified.");
        getInternalRelations().add(relation);
        relation.setPerson(this);
     }

     /**
      * Remove a Relation for this person. This method takes care of Bidirectional setting of
      * Relation's person.
      *
      * @param relation
      */
     public void removeRelation(Relation relation) {
        Validate.notNull(relation, "Null relation specified.");
        getInternalRelations().remove(relation);
        relation.setPerson(null);
     }

     public void removeAllRelations() {
        this.getInternalRelations().clear();
     }

     public Character getVOAIndicator() {
         return VOAIndicator;
     }

     public void setVOAIndicator(Character VOAIndicator) {
         this.VOAIndicator = VOAIndicator;
     }

     /**
      * Derived value for VOAOnly.
      * @return
      */
     public boolean isVOAOnly() {
         return (VOAIndicator==null?false: VOAIndicator.equals('2'));
     }

	public Date getClassIIDentalApplicationDueBefore() {
		return classIIDentalApplicationDueBefore;
	}

	public void setClassIIDentalApplicationDueBefore(
			Date classIIDentalApplicationDueBefore) {
		this.classIIDentalApplicationDueBefore = classIIDentalApplicationDueBefore;
	}

	public Boolean getEligibleForClassIIDental() {
		return eligibleForClassIIDental;
	}

	public void setEligibleForClassIIDental(Boolean eligibleForClassIIDental) {
		this.eligibleForClassIIDental = eligibleForClassIIDental;
	}

	public Boolean getNeedCareDueToAccident() {
		return needCareDueToAccident;
	}

	public void setNeedCareDueToAccident(Boolean needCareDueToAccident) {
		this.needCareDueToAccident = needCareDueToAccident;
	}

	public Boolean getNeedCareDueToInjury() {
		return needCareDueToInjury;
	}

	public Name getFathersName() {
		return fathersName;
	}

	public void setFathersName(Name fathersName) {
		this.fathersName = fathersName;
	}

	public Name getMothersName() {
		return mothersName;
	}

	public void setMothersName(Name mothersName) {
		this.mothersName = mothersName;
	}

	public void setNeedCareDueToInjury(Boolean needCareDueToInjury) {
		this.needCareDueToInjury = needCareDueToInjury;
	}

	public void setEnrollmentSignatureDate(Date date) {
	   enrollmentSignatureDate = date;
	}
	public Date getEnrollmentSignatureDate() {
	   return enrollmentSignatureDate;
	}

   /* Returns a collection of PreferredFacility Objects. If no preferredFacilities exists for this person,
    * this method will return empty Set.
    *
    * @return Set - Set of PreferredFacilities
    */
   public Set getPreferredFacilities() {
      return Collections.unmodifiableSet(getInternalPreferredFacilities());
   }

   /* Returns a single VAFacility of the PreferredFacility Object for backward compatible for old code (ilog rule)
    * that requires just one PF with VAFacility.
    * If no preferredFacilities exists for this person, this method will return null.
    *
    * @return VAFacility
    */
   public VAFacility getPreferredFacility() {
      if (getPreferredFacilities().size()>0)
    	  return ((PreferredFacility)getPreferredFacilities().iterator().next()).getFacility();

      return null;
   }

	/**
	* Getter - for hibernate use only.
	*
	* @return
	*/
	private Set getInternalPreferredFacilities() {
      if( this.internalPreferredFacilities == null ) {
         this.internalPreferredFacilities = new HashSet();
      }
      return this.internalPreferredFacilities;
	}

	/**
	* Setter - for hibernate use only.
	*
	* @param preferredFacilities
	*/
	private void setInternalPreferredFacilities(Set preferredFacilities) {
      this.internalPreferredFacilities = preferredFacilities;
	}

	/**
	* Add a PreferredFacility for this person. This method takes care of
	* Bidirectional setting of PreferredFacility person.
	*
	* @param preferredFacility
	*/
	public void addPreferredFacility(
			PreferredFacility preferredFacility) {
      Validate.notNull(preferredFacility,
            "Null preferredFacility specified.");
      getInternalPreferredFacilities().add(preferredFacility);
      preferredFacility.setPerson(this);
	}

	/**
	* Add a set of preferredFacility for this person. This method takes care of
	* Bidirectional setting of PreferredFacility person.
	*
	* @param preferredFacilities
	*/
	public void addAllPreferredFacilities(Set preferredFacilities) {
      Validate.notNull(preferredFacilities,
            "Empty set of preferredFacilities specified.");

      this.setOwner(preferredFacilities);
      Set internal = this.getInternalPreferredFacilities();
      internal.addAll(preferredFacilities);
	}

	/**
	 * Remove an PreferredFacility for this person. This method takes care of
	 * Bidirectional setting of PreferredFacility's person.
	 *
	 * @param preferredFacility
	 */
	public void removePreferredFacility(PreferredFacility preferredFacility) {
		Validate
				.notNull(preferredFacility, "Null PreferredFacility specified.");
		preferredFacility.setPerson(null);
		getInternalPreferredFacilities().remove(preferredFacility);
	}

	public void removeAllPreferredFacilities() {
		this.getInternalPreferredFacilities().clear();
	}

   public PreferredFacility getPreferredFacilityByEntityKey(EntityKey identifier) {
	      return (PreferredFacility)getEntityByEntityKey(getPreferredFacilities(), identifier);
	   }

	/*
	 * Returns a collection of PatientProviderAssignment Objects. If no
	 * patientProviderAssignment exists for this person, this method will return
	 * empty Set.
	 *
	 * @return Set - Set of PatientProviderAssignment
	 */
	public Set getProviderAssignments() {
		return Collections.unmodifiableSet(getInternalProviderAssignments());
	}

	/**
	 * Getter - for hibernate use only.
	 *
	 * @return
	 */
	private Set getInternalProviderAssignments() {
      if( this.internalProviderAssignments == null ) {
         this.internalProviderAssignments = new HashSet();
      }
      return this.internalProviderAssignments;
	}

	/**
	* Setter - for hibernate use only.
	*
	* @param pAssignments
	*/
	private void setInternalProviderAssignments(Set providerAssignments) {
      this.internalProviderAssignments = providerAssignments;
	}

	/**
	* Add a PatientProviderAssignment for this person. This method takes care of
	* Bidirectional setting of PatientProviderAssignment person.
	*
	* @param preferredFacility
	*/
	public void addProviderAssignment(
			PatientProviderAssignment providerAssignment) {
      Validate.notNull(providerAssignment,
            "Null ProviderAssignment specified.");
      getInternalProviderAssignments().add(providerAssignment);
      providerAssignment.setPerson(this);
	}

	/**
	* Add a set of PatientProviderAssignments for this person. This method takes care of
	* Bidirectional setting of PatientProviderAssignment person.
	*
	* @param providerAssignments
	*/
	public void addAllProviderAssignments(Set providerAssignments) {
      Validate.notNull(providerAssignments,
            "Empty set of providerAssignments specified.");

      this.setOwner(providerAssignments);
      Set internal = this.getInternalProviderAssignments();
      internal.addAll(providerAssignments);
	}

	/**
	 * Remove an PatientProviderAssignment for this person. This method takes care of
	 * Bidirectional setting of PatientProviderAssignment person.
	 *
	 * @param providerAssignment
	 */
	public void removeProviderAssignment(PatientProviderAssignment providerAssignment) {
		Validate
				.notNull(providerAssignment, "Null PatientProviderAssignments specified.");
		providerAssignment.setPerson(null);
		getInternalProviderAssignments().remove(providerAssignment);
	}

	public void removeAllProviderAssignments() {
		this.getInternalProviderAssignments().clear();
	}

	public int getIdmMatchType() {
		return idmMatchType;
	}

	public void setIdmMatchType(int idmMatchType) {
		this.idmMatchType = idmMatchType;
	}

	public Set getInternalDeliveryPreferences() {
		if (internalDeliveryPreferences == null)
		{
			internalDeliveryPreferences = new HashSet();
		}
		return internalDeliveryPreferences;
	}

	public void setInternalDeliveryPreferences(Set internalDeliveryPreferences) {
		this.internalDeliveryPreferences = internalDeliveryPreferences;
	}

	public DeliveryPreference getDeliveryPreference()
	{
		if (internalDeliveryPreferences != null && internalDeliveryPreferences.size() >0)
		{
			return (DeliveryPreference)internalDeliveryPreferences.iterator().next();
		}
		return null;
	}

	public void addDeliveryPreference(DeliveryPreference deliveryPreference)
	{
	      Validate.notNull(deliveryPreference, "Null Delivery Preference specified.");
	      getInternalDeliveryPreferences().add(deliveryPreference);
	      deliveryPreference.setPerson(this);
	}

	public boolean isVoaFormProcessPendingStatus() {
		return voaFormProcessPendingStatus;
	}

	public void setVoaFormProcessPendingStatusTrue() {
		this.voaFormProcessPendingStatus = true;
	}

	// CCR 12062 add support for transient events... not persisted
	public Map getChangeEvents() {
		if (changeEvents == null) {
			changeEvents = new HashMap();
		}
		return changeEvents;
	}

	public void setChangeEvent(String key, String event) {
		getChangeEvents().put(key, event);
	}

	//CCR 12176 set the flag to know the 200ESR Correlation is added - new person just added
	public boolean isEsrCorrelationAdded() {
		return esrCorrelationAdded;
	}

	public void setEsrCorrelationAdded(boolean esrCorrelationAdded) {
		this.esrCorrelationAdded = esrCorrelationAdded;
	}

	//CCR12665
	public Set getSiteIdentities() {
		return siteIdentities;
	}

	public void setSiteIdentities(Set siteIdentities) {
		this.siteIdentities = siteIdentities;
	}

    public SelfIdentifiedGenderIdentity getSelfIdentifiedGenderIdentity() {
        return selfIdentifiedGenderIdentity;
    }

    public void setSelfIdentifiedGenderIdentity(SelfIdentifiedGenderIdentity selfIdentifiedGenderIdentity) {
        this.selfIdentifiedGenderIdentity = selfIdentifiedGenderIdentity;
    }

	public boolean isJustAdded() {
		return justAdded;
	}

	public void setJustAdded(boolean justAdded) {
		this.justAdded = justAdded;
	}

    /**
     * CR 13726
     * Helper method to get the Veterans Choice Eligibilities Determination.
     * See the table VCESTATUSTYPE
     *
     * @param relationshipcode
      *
     * @return the relation of the specified type.
     */
	public String getVetChoiceStat() {
		if (vcEligibilities == null || vcEligibilities.size() == 0) {
			return "";
		}
		else { // Set should contain ONLY ONE element
			VcEligibility vetChoice = (VcEligibility) vcEligibilities.iterator().next();
			return vetChoice.getVceStatusType().getCode();
		}
	}
	
}