/********************************************************************
 * Copyright © 2004 EDS. All rights reserved
 ********************************************************************/
//Package
package gov.va.med.esr.messaging.builder.message;

//Framework Classes
import gov.va.med.fw.hl7.segment.ZDP;
import gov.va.med.fw.util.builder.BuilderException;

import gov.va.med.esr.common.model.financials.DependentFinancials;
import gov.va.med.esr.common.model.financials.RelationFinancials;
import gov.va.med.esr.common.model.financials.SpouseFinancials;
import gov.va.med.esr.common.model.lookup.PseudoSSNReason;
import gov.va.med.esr.common.model.lookup.Relationship;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.person.Dependent;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.Relation;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.Spouse;
import gov.va.med.esr.messaging.constants.HL7Constants;

/**
 * Class to build the ZDP segment.
 * 
 * @author Alex Yoon
 * @author Rajiv Patnaik
 * @version 1.0
 */
public class ZDPBuilder extends AbstractSegmentBuilder
{
    /**
    * An instance of serialVersionUID 
    */
   private static final long serialVersionUID = -6937236836985429868L;
   
   private static final String PSEUDO_SSN_SUFFIX = "P";

   public ZDPBuilder()
    {
        super();
    }

    /**
     * Method to build the ZDP segment.
     * 
     * @param metaData
     *            The parameter object used to build the a ZDP segment.
     * @return The ZDP segment.
     */
    public Object build(ZDPMetaData metaData) throws BuilderException
    {
        if ((metaData == null) || (metaData.getEntity() == null)
                || !(metaData.getEntity() instanceof Person)
                || metaData.getSetId() == null)
        {
            throw new BuilderException(
                    "Invalid input parameter to build a segment");
        }

        ZDP segment = new ZDP();

        Relationship relationship = metaData.getRelationship();
        RelationFinancials relationFinancials = metaData.getRelationFinancials();
        
        //Seq 1-12 for spouse and 1,-6, 9-12 for dependents

        segment.setSetID(metaData.getSetId());
        
        if(relationFinancials != null && relationship != null)
        {
            if (Relationship.CODE_SPOUSE.getName().equals(relationship.getCode()))
            {
                segment = buildSpouseZDP(segment, relationFinancials);
            } else//it is a dependent
            {
                segment = buildDependentZDP(segment, relationFinancials);
            }
        } else if(metaData.getSetId() == HL7Constants.SPOUSE_SETID)//For spouse, setId = 1
        {
            //CR3494 - relationship of Spouse (Sequence 6) is always sent regardless if there is a spouse or not.
            segment.setRelationship(Relationship.CODE_SPOUSE.getCode());
        }


        return segment;
    }
   
    /**
     * @param segment
     * @param relationFinancials
     * @throws BuilderException
     */
    private ZDP buildSpouseZDP(ZDP segment, RelationFinancials relationFinancials) throws BuilderException
    {
        SpouseFinancials spouseFinancials = (SpouseFinancials)relationFinancials;
        Spouse spouse = spouseFinancials.getReportedOn();
        
        segment = buildRelationZDP(segment, spouse);
        //Seq 7
        //segment.setInternalEntryNumber() //Not needed
        //Seq 8
        segment.setSpouseMaidenName(spouse.getMaidenName());
        
        return segment;
    }

    /**
     * @param segment
     * @param relationFinancials
     * @throws BuilderException
     */
    private ZDP buildDependentZDP(ZDP segment, RelationFinancials relationFinancials) throws BuilderException
    {
        DependentFinancials dependentFinancials = (DependentFinancials)relationFinancials;
        Dependent dependent = dependentFinancials.getReportedOn();
        
        return buildRelationZDP(segment, dependent);
    }

    /**
     * @param segment
     * @param relation
     * @return
     * @throws BuilderException
     */
    private ZDP buildRelationZDP(ZDP segment, Relation relation) throws BuilderException
    {
        //Seq 2
        segment.setDependentName(ElementFormatter
                .formatName(relation.getName()));
        //Seq 3
        segment.setSex(super.build(getGenderBuilder(), relation.getGender()));
        //Seq 4
        segment.setBirthDate(DateFormatter.formatDate(relation.getDob()));
        
        SSN ssn = relation.getOfficialSsn();
        SSN pseudoSsn = relation.getPseudoSsn();
        
        //Seq 5        
        segment.setSSN(ssn == null ? getSsnText(pseudoSsn, true) : getSsnText(ssn, false));
        
        //Seq 6
        segment.setRelationship(relation.getRelationship() != null ? relation
                .getRelationship().getCode() : null);

        //Seq 9
        segment.setDependentDate(DateFormatter.formatDate(relation
                .getStartDate()));
        //seq 10
        String pseudoSsnReason = ssn == null && pseudoSsn != null ? getPseudoSsnReason(pseudoSsn) : null;
        segment.setPseudoSSNReason(pseudoSsnReason);
        //Seq 11
        segment.setInactivationDate(DateFormatter.formatDate(relation
                .getEndDate()));
        
        //Seq 12
        String sSaVerificationStatus=null;
        if(ssn!=null)
        {        
	        SSAVerificationStatus verificationStatus= ssn.getSsaVerificationStatus();
	        if(verificationStatus!=null && ( 
	        		verificationStatus.getCode().equals(SSAVerificationStatus.VERIFIED.getCode())||
	        		verificationStatus.getCode().equals(SSAVerificationStatus.INVALID_PER_SSA.getCode())
	        	))
	        {
	        	sSaVerificationStatus=super.build(verificationStatus);
	        }
        }
        segment.setSSNVerificationStatus(sSaVerificationStatus);
      
        return segment;
    }

    private String getPseudoSsnReason(SSN pseudoSsn) {
        PseudoSSNReason reason = pseudoSsn.getPseudoSSNReason();
        return reason == null ? null : reason.getCode();
    }

    /**
     * Vista always appends a "P" when it sends a Pseudo SSN but the Pseudo SSN created by ESR 
     * does not contain one. ESR needs to strip off the "P" before sending it to Vista. If not 
     * Vista, will add another "P" while sending the next message and the "P"s just keep adding up.
     * (defect 5608)
     * 
     * @param ssn
     * @param isPseudoSSN
     * @return the SSN text without the P in case of a SSN. 
     */
    private String getSsnText(SSN ssn, boolean isPseudoSSN) {
    	String ssnText = ssn != null ? ssn.getSsnText() : null;
    	
    	if(isPseudoSSN && ssnText != null && ssnText.endsWith(PSEUDO_SSN_SUFFIX))
    	{
    		ssnText = ssnText.substring(0, ssnText.indexOf(PSEUDO_SSN_SUFFIX));
    	}
        return ssnText;
    }
}    
