package gov.va.med.esr.service;

// Java Classes
import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.model.lookup.Gender;
import gov.va.med.esr.common.model.lookup.NameType;
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.VAFacility;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.AuditInfo;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.person.idmgmt.types.MultipleBirthIndicator;
import gov.va.med.ps.model.PatientIdentifier;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

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

/**
 * Pojo for capturing Person identity traits, as they pertain to ESR.
 * <p/>
 * Created Aug 23, 2005 9:42:56 PM
 *
 * @author DNS   BOHMEG
 */
public class PersonIdentityTraits extends AbstractEntity
{
	public static final String UPDATE_STATUS_ACCEPTED = "ACCEPTED";
	public static final String UPDATE_STATUS_PENDING = "PENDING";
	public static final String UPDATE_STATUS_REJECTED = "REJECTED";


	public static final int POTENTIAL_MATCH = 1;
	public static final int EXACT_MATCH = 2;
    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = -781467991435230932L;

    private Set names = new HashSet();

    //CCR12665-stores site identities retrieved by 1305 Comp1 calls
    private Set siteIdentities = new HashSet();

    private BirthRecord birthRecord;

    private Gender gender;

    private SSN ssn;  // note that PSIM only maintains a singular SSN (even though ESR Person object supports multiple)

    private VPIDEntityKey vpid;

    private boolean hasPendingUpdates;

    private boolean isDeprecated;

    private boolean retrievedWithDeprecatedVPID;

    private String mothersMaidenName;

    private AuditInfo auditInfo;

    private String IDState = null;
    
    private String edipi = null;

	private SelfIdentifiedGenderIdentity sigi = null;

    //private Address address = null;
    Set addresses = null;

    // CCR 10471 ADD A PERSON
    private VAFacility preferredFacilty;
    private MultipleBirthIndicator multiBirth;
    private String placeOfBirthCity;
    private String placeOfBirthState;
    private boolean addAPerson;

    private String patientType;
    private boolean isVeteran;
    private boolean isServiceConnected;
    private int idmMatchType;

    //CCR 11403; added date of death
    private String dateOfDeathText = null;

    private String has200ESRCorrelation = null; //"Y", "N", null (unknown)

    private transient List<PatientIdentifier> allCorrelations = null; //CCR 12789

	/** Do not call this method.  It is for use by XML Serialization only. */
   public PersonIdentityTraits() {
    	super();
    }

	/**
     * @see gov.va.med.fw.model.AbstractEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
     */
    protected void buildToString(ToStringBuilder builder)
    {
        builder.append("names", names);
        builder.append("birthRecord", birthRecord);
        builder.append("gender", gender);
        builder.append("ssn", ssn);
        builder.append("vpid", vpid);
        builder.append("edipi", edipi);
        builder.append("hasPendingUpdates", hasPendingUpdates);
        builder.append("isDeprecated", isDeprecated);
        builder.append("auditInfo", auditInfo);

        //CCR 10471 ADD A PERSON
        builder.append("preferredFacility", preferredFacilty);
        builder.append("multipleBirth", multiBirth);
        builder.append("placeOfBirthCity", placeOfBirthCity);
        builder.append("placeOfBirthState", placeOfBirthState);
        builder.append("addresses", addresses);
        builder.append("patientType", patientType);
        builder.append("isVeteran", isVeteran);
        builder.append("isServiceConnected", isServiceConnected);
        builder.append("idmMatchType", idmMatchType);
    }

    /**
     * @return Returns the gender.
     */
    public Gender getGender()
    {
        return gender;
    }

    /**
     * @param gender The gender to set.
     */
    public void setGender(Gender gender)
    {
        this.gender = gender;
    }

    /**
     * @return Returns the names.
     */
    public Set getNames()
    {
        return names;
    }

    public Name getLegalName()
    {
        return names != null ? Name.getNameOfType(names, NameType.LEGAL_NAME
            .getName()) : null;
    }

    public void addName(Name name)
    {
        names.add(name);
    }

    /**
     * @param names The names to set.
     */
    public void setNames(Set names)
    {
        this.names = names;
    }


    //CCR12665 - getter and setter
    public Set getSiteIdentities() {
		return siteIdentities;
	}

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

	public SSN getSsn()
    {
        return ssn;
    }

    public String getSsnText()
    {
        return ssn != null ? ssn.getFormattedSsnText() : null;
    }

    public void setSsn(SSN ssn)
    {
        this.ssn = ssn;
    }

    /**
     * @return Returns the birthRecord.
     */
    public BirthRecord getBirthRecord()
    {
        return birthRecord;
    }

    /**
     * @param birthRecord The birthRecord to set.
     */
    public void setBirthRecord(BirthRecord birthRecord)
    {
        this.birthRecord = birthRecord;
    }

    /**
     * @return Returns the vpid.
     */
    public VPIDEntityKey getVpid()
    {
        return vpid;
    }

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

    /**
     * @return Returns the hasPendingUpdates.
     */
    public boolean isHasPendingUpdates()
    {
        return hasPendingUpdates;
    }


    /**
     * @param hasPendingUpdates The hasPendingUpdates to set.
     */
    public void setHasPendingUpdates(boolean hasPendingUpdates)
    {
        this.hasPendingUpdates = hasPendingUpdates;
    }

    /**
     * This means this objects traits represent a deprecated Person in PSIM.
     *
     * @return Returns the isDeprecated.
     */
    public boolean isDeprecated()
    {
        return isDeprecated;
    }

    /**
     * @param isDeprecated The isDeprecated to set.
     */
    public void setDeprecated(boolean isDeprecated)
    {
        this.isDeprecated = isDeprecated;
    }


	public boolean isServiceConnected() {
		return isServiceConnected;
	}

	public void setServiceConnected(boolean isServiceConnected) {
		this.isServiceConnected = isServiceConnected;
	}

	public boolean isVeteran() {
		return isVeteran;
	}

	public void setVeteran(boolean isVeteran) {
		this.isVeteran = isVeteran;
	}

	public String getPatientType() {
		return patientType;
	}

	public void setPatientType(String patientType) {
		this.patientType = patientType;
	}

	public Set getAddresses() {
		return addresses;
	}

	public void setAddresses(Set addresses) {
		this.addresses = addresses;
	}

   public void addAddress(Address address) {
		Validate.notNull(address, "Null address specified.");
		if ( addresses == null ) {
			addresses = new HashSet();
		}
		addresses.add(address);
	}


   public Address getAddressByType(String addressTypeName ) {
	   if ( addresses != null && addresses.size() > 0 ){
		   return Address.getAddressOfType(addresses,addressTypeName);
	   }
	   return null;
   }

	public boolean containsOnlySSN()
    {
        String ssn = getSsn() != null ? getSsn().getSsnText() : null;
        String firstName = getLegalName() != null ? getLegalName().getGivenName() : null;
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;
        ImpreciseDate dob = getBirthRecord() != null ? getBirthRecord().getBirthDate() : null;
        Gender gender = getGender();

        boolean result = false;
        if (vpid == null && StringUtils.isNotBlank(ssn) && StringUtils.isBlank(firstName) &&
            StringUtils.isBlank(lastName) &&
            dob == null && gender == null)
            result = true;
        return result;
    }

    public boolean hasOfficialSSN()
    {
        SSNType myType = getSsn() != null ? getSsn().getType() : null;
        return myType != null && SSNType.CODE_ACTIVE.getCode().equals(myType.getCode());
    }

    public boolean containsOnlyFullName()
    {
        String ssn = getSsn() != null ? getSsn().getSsnText() : null;
        String firstName = getLegalName() != null ? getLegalName().getGivenName() : null;
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;
        ImpreciseDate dob = getBirthRecord() != null ? getBirthRecord().getBirthDate() : null;
        Gender gender = getGender();

        boolean result = false;
        if (vpid == null && StringUtils.isBlank(ssn) && StringUtils.isNotBlank(firstName) &&
            StringUtils.isNotBlank(lastName) &&
            dob == null && gender == null)
            result = true;
        return result;
    }

    public boolean containsAtLeastFullName()
    {
        String firstName = getLegalName() != null ? getLegalName().getGivenName() : null;
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;

        boolean result = false;
        if (StringUtils.isNotBlank(firstName) && StringUtils.isNotBlank(lastName))
            result = true;
        return result;
    }

    public boolean containsOnlyLastNameAndDOB()
    {
        String ssn = getSsn() != null ? getSsn().getSsnText() : null;
        String firstName = getLegalName() != null ? getLegalName().getGivenName() : null;
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;
        ImpreciseDate dob = getBirthRecord() != null ? getBirthRecord().getBirthDate() : null;
        Gender gender = getGender();

        boolean result = false;
        if (vpid == null && StringUtils.isBlank(ssn) && StringUtils.isBlank(firstName) &&
            StringUtils.isNotBlank(lastName) &&
            dob != null && gender == null)
            result = true;
        return result;
    }

    public boolean containsAtLeastLastNameAndDOB()
    {
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;
        ImpreciseDate dob = getBirthRecord() != null ? getBirthRecord().getBirthDate() : null;

        boolean result = false;
        if (StringUtils.isNotBlank(lastName) && dob != null)
            result = true;
        return result;
    }

    public boolean containsSsnDOBGender()
    {
        String ssn = getSsn() != null ? getSsn().getSsnText() : null;
        String lastName = getLegalName() != null ? getLegalName().getFamilyName() : null;
        ImpreciseDate dob = getBirthRecord() != null ? getBirthRecord().getBirthDate() : null;
        Gender gender = getGender();

        boolean result = false;
        if (vpid == null && StringUtils.isBlank(lastName) && StringUtils.isNotBlank(ssn) && dob != null && gender != null)
            result = true;
        return result;
    }

    /**
     * This does not mean the traits in this object are deprecated.   It just means that these
     * traits were actually obtained by using a deprecated VPID.
     *
     * @return Returns the retrievedWithDeprecatedVPID.
     */
    public boolean isRetrievedWithDeprecatedVPID()
    {
        return retrievedWithDeprecatedVPID;
    }

    /**
     * @param retrievedWithDeprecatedVPID The retrievedWithDeprecatedVPID to set.
     */
    public void setRetrievedWithDeprecatedVPID(boolean retrievedWithDeprecatedVPID)
    {
        this.retrievedWithDeprecatedVPID = retrievedWithDeprecatedVPID;
	}

	public boolean isAcceptedStatus() {
		return "A".equalsIgnoreCase(auditInfo != null ? auditInfo.getStatus() : StringUtils.EMPTY);
	}

	public boolean isPendingStatus() {
		return "P".equalsIgnoreCase(auditInfo != null ? auditInfo.getStatus() : StringUtils.EMPTY);
	}

	public boolean isRejectedStatus() {
		// assumption being made here...
		return !isAcceptedStatus() && !isPendingStatus();
	}

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

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

	public boolean equals(Object o) {
		super.getLogger(); // this just initializes logger and allows us to turn on logging for this class
		return super.equals(o);
	}

    /**
	 * @return Returns the auditInfo.
	 */
	public AuditInfo getAuditInfo() {
		return auditInfo;
	}

	/**
	 * @param auditInfo The auditInfo to set.
	 */
	public void setAuditInfo(AuditInfo auditInfo) {
		this.auditInfo = auditInfo;
	}

	public String getIDState() {
		return IDState;
	}

	public void setIDState(String state) {
		IDState = state;
	}

    public String getEdipi() {
		return edipi;
	}

	public void setEdipi(String edipi) {
		this.edipi = edipi;
	}

	public MultipleBirthIndicator getMultiBirth() {
		return multiBirth;
	}

	public void setMultiBirth(MultipleBirthIndicator multiBirth) {
		this.multiBirth = multiBirth;
	}

	public String getPlaceOfBirthCity() {
		return placeOfBirthCity;
	}

	public void setPlaceOfBirthCity(String placeOfBirthCity) {
		this.placeOfBirthCity = placeOfBirthCity;
	}

	public String getPlaceOfBirthState() {
		return placeOfBirthState;
	}

	public void setPlaceOfBirthState(String placeOfBirthState) {
		this.placeOfBirthState = placeOfBirthState;
	}

	public VAFacility getPreferredFacilty() {
		return preferredFacilty;
	}

	public void setPreferredFacilty(VAFacility preferredFacilty) {
		this.preferredFacilty = preferredFacilty;
	}

	public boolean isAddAPerson() {
		return addAPerson;
	}

	public void setAddAPerson(boolean addAPerson) {
		this.addAPerson = addAPerson;
	}

	public int getIdmMatchType() {
		return idmMatchType;
	}

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

	//date of death text from IdM <deceasedTime value=yyyyMMdd/>
	public String getDateOfDeathText() {
		return dateOfDeathText;
	}

	//date of death text from IdM <deceasedTime value=yyyyMMdd/>
	public void setDateOfDeathText(String dateOfDeathText) {
		this.dateOfDeathText = dateOfDeathText;
	}

	//CCR 11758
	/**
	 * return "Y", "N", null (unknown)
	 */
	public String has200ESRCorrelation() {
		//CCR 11758, if 200ESR Correlation not found, set to "N";
		return (has200ESRCorrelation != null) ? has200ESRCorrelation : "N";
	}

	/**
	 * set //"Y", "N", null (unknown)
	 * @param has200ESRCorrelation
	 */
	public void set200ESRCorrelation(String has200ESRCorrelation) {
		this.has200ESRCorrelation = has200ESRCorrelation;
	}

	public List<PatientIdentifier> getAllCorrelations() {
		return allCorrelations;
	}

	public void setAllCorrelations(List<PatientIdentifier> allCorrelations) {
		this.allCorrelations = allCorrelations;
	}

	public SelfIdentifiedGenderIdentity getSigi() {
		return sigi;
	}

	public void setSigi(SelfIdentifiedGenderIdentity sigi) {
		this.sigi = sigi;
	}


}
