/********************************************************************
 * Copyright © 2004 EDS. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.builder.entity;

// Java Classes
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

import gov.va.med.esr.common.model.financials.Hardship;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.financials.IncomeTestStatus;
import gov.va.med.esr.common.model.lookup.IncomeTestSource;
import gov.va.med.esr.common.model.lookup.IncomeTestType;
import gov.va.med.esr.common.model.lookup.MeansTestStatus;
import gov.va.med.esr.common.model.lookup.WkfCaseStatusType;
import gov.va.med.esr.common.model.party.Address;

// Messaging Classes

/**
 * Builds a rated disability from a message and a person if elements in the ZRD
 * segments are present
 * 
 * @author Carlos Ruiz
 * @version 1.0
 */
public class IncomeTestBuilder extends EntityBuilder
{
    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = 6476065921296864806L;

    private Builder addressBuilder;

    private Builder hardshipBuilder;

    private Builder incomeVerificationStatusBuilder;

    private Builder sourceBuilder;

    private Builder statusBuilder;

    private Builder typeBuilder;
    
    private Builder mtStatusBuilder;
    
    private Builder wfCaseStatusBuilder;

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

    public Builder getAddressBuilder()
    {
        return this.addressBuilder;
    }

    public void setAddressBuilder(Builder addressBuilder)
    {
        this.addressBuilder = addressBuilder;
    }

    public Builder getHardshipBuilder()
    {
        return this.hardshipBuilder;
    }

    public void setHardshipBuilder(Builder hardshipBuilder)
    {
        this.hardshipBuilder = hardshipBuilder;
    }

    public Builder getIncomeVerificationStatusBuilder()
    {
        return this.incomeVerificationStatusBuilder;
    }

    public void setIncomeVerificationStatusBuilder(
            Builder incomeVerificationStatusBuilder)
    {
        this.incomeVerificationStatusBuilder = incomeVerificationStatusBuilder;
    }

    public Builder getSourceBuilder()
    {
        return this.sourceBuilder;
    }

    public void setSourceBuilder(Builder sourceBuilder)
    {
        this.sourceBuilder = sourceBuilder;
    }

    public Builder getStatusBuilder()
    {
        return this.statusBuilder;
    }

    public void setStatusBuilder(Builder statusBuilder)
    {
        this.statusBuilder = statusBuilder;
    }

    public Builder getTypeBuilder()
    {
        return this.typeBuilder;
    }

    public void setTypeBuilder(Builder typeBuilder)
    {
        this.typeBuilder = typeBuilder;
    }

    public Builder getMtStatusBuilder() {
        return this.mtStatusBuilder;
    }

    public void setMtStatusBuilder(Builder mtStatusBuilder) {
        this.mtStatusBuilder = mtStatusBuilder;
    }

    public IncomeTest build(IncomeTestMetaData metaData)
            throws BuilderException
    {
    	//if the incoming income test indicates a delete request
    	if(metaData.isContainsDeleteRequest()){
        	
    		//return no income test;
        	return null;
        }
    	
        IncomeTest input = metaData.getEntity();
        
        //if there is no existing income test, and the incoming test indicates no changes
        if (input == null && metaData.getStatuses()==null){
        	
        	//return no income test
        	return null;
        }
        
        IncomeTest output = (input == null) ? new IncomeTest() : input;

        this.transfer(output, metaData);       
        return output;
    }

    private Address buildAddress(Address input, AddressMetaData metaData)
            throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        } else
        {
            metaData.setEntity(input);
            return (Address) this.addressBuilder.build(metaData);
        }
    }

    private Hardship buildHardship(Hardship input, HardshipMetaData metaData)
            throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        } else
        {
            metaData.setEntity(input);
            return (Hardship) this.hardshipBuilder.build(metaData);
        }
    }

    private MeansTestStatus buildIncomeVerificationStatus(
            MeansTestStatus input, String code) throws BuilderException
    {
        return super.shouldDelete(code) ? null : (MeansTestStatus) super.build(
                this.incomeVerificationStatusBuilder, input, code);
    }

    private IncomeTestSource buildSource(IncomeTestSource input, String code)
            throws BuilderException
    {
        return super.shouldDelete(code) ? null : (IncomeTestSource) super
                .build(this.sourceBuilder, input, code);
    }

    private IncomeTestStatus buildStatus(IncomeTestStatus input,
            IncomeTestStatusMetaData metaData) throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        } else
        {
            metaData.setEntity(input);
            return (IncomeTestStatus) this.statusBuilder.build(metaData);
        }
    }

    private void buildStatuses(IncomeTest input,
            IncomeTestStatusMetaData[] metaData) throws BuilderException
    {
        Set toAdd = new HashSet();

        for (int index = 0; index < ((metaData == null) ? 0 : metaData.length); index++)
        {
            this.processStatus(toAdd, metaData[index]);
        }

        input.removeAllStatuses();

        for (Iterator i = toAdd.iterator(); i.hasNext();)
        {
            input.addStatus((IncomeTestStatus) i.next());
        }
    }

    private IncomeTestType buildType(IncomeTestType input, String code)
            throws BuilderException
    {
        return super.shouldDelete(code) ? null : (IncomeTestType) super.build(
                this.typeBuilder, input, code);
    }

    private MeansTestStatus buildMeansTestStatus(MeansTestStatus input, String code)
    throws BuilderException
    {
        return super.shouldDelete(code) ? null : (MeansTestStatus) super.build(
            this.mtStatusBuilder, input, code);
    }
    
    private WkfCaseStatusType buildWorkflowCaseStatus(WkfCaseStatusType input, String code)
    throws BuilderException
    {
    	return super.shouldDelete(code) ? null : (WkfCaseStatusType) super
        .build(this.wfCaseStatusBuilder, input, code);
    }
 
    private void processStatus(Set toAdd, IncomeTestStatusMetaData metaData)
            throws BuilderException
    {
        IncomeTestStatus value = this.buildStatus(null, metaData);
        if (value != null)
        {
            toAdd.add(value);
        }
    }

    private void transfer(IncomeTest input, IncomeTestMetaData metaData)
            throws BuilderException
    {
        //Usually the ZMT segments will be for IncomeTestTypes 1,2,4 OR 1,2 OR
        // 1,4 OR 2,4
        //The first ZMT segment will contain the IncomeTest data (and will be
        // the PrimaryIncomeTest)
        //and the rest of the segments may contain only the status or they
        //could contain more IncomeTestData but will be repeating as the first
        // segment. So the first segment will be the ZMT segment from which the
        // common
        // IncomeTest data will be populated.
        input.setAdjudicationDate(super.build(input.getAdjudicationDate(),
                metaData.getAdjudicationDate()));
        input.setAgreesToPayDeductible(super.build(input
                .getAgreesToPayDeductible(), metaData
                .getAgreesToPayDeductible()));
        input.setComments(super.build(input.getComments(), metaData
                .getComments()));
        input.setDateMTNoLongerRequired(super.build(input
                .getDateMTNoLongerRequired(), metaData
                .getDateMTNoLongerRequired()));
        input.setDeductibleExpenses(super.build(input.getDeductibleExpenses(),
                metaData.getDeductibleExpenses()));
        input.setDiscloseFinancialInformation(super.build(input
                .getDiscloseFinancialInformation(), metaData
                .getDiscloseFinancialInformation()));
        input.setEffectiveDate(super.build(input.getEffectiveDate(), metaData
                .getEffectiveDate()));
        input.setGmtAddress(this.buildAddress(input.getGmtAddress(), metaData
                .getGMTAddress()));
        input.setGmtThresholdAmount(super.build(input.getGmtThresholdAmount(),
                metaData.getGMTThresholdAmount()));
        input.setHardship(this.buildHardship(input.getHardship(), metaData
                .getHardship()));
        input.setIncomeVerificationStatus(this.buildIncomeVerificationStatus(
                input.getIncomeVerificationStatus(), metaData
                        .getIncomeVerificationStatus()));
        input.setIncomeVerificationStatusDate(super.build(input
                .getIncomeVerificationStatusDate(), metaData
                .getIncomeVerificationStatusDate()));
        input.setIncomeYear(super.buildYear(input.getIncomeYear(), metaData
                .getIncomeYear()));
        input.setIVMTestCompletionDate(super.build(input
                .getIVMTestCompletionDate(), metaData
                .getIVMTestCompletionDate()));
        input.setNetWorth(super.build(input.getNetWorth(), metaData
                .getNetWorth()));
        input.setPreviousYearThresholdApplies(super.build(input
                .getPreviousYearThresholdApplies(), metaData
                .getPreviousYearThresholdApplies()));
        input.setPrimaryIncomeTest(super.build(input.isPrimaryIncomeTest(),
                metaData.getPrimaryIncomeTest()));
        input.setReasonMTNoLongerRequired(super.build(input
                .getReasonMTNoLongerRequired(), metaData
                .getReasonMTNoLongerRequired()));
        input.setRefusedToSign(super.build(input.getRefusedToSign(), metaData
                .getRefusedToSign()));
        input.setSiteConductingTest(super.build(input.getSiteConductingTest(),
                metaData.getSiteConductingTest()));
        input.setSource(this.buildSource(input.getSource(), metaData
                .getSource()));
        input.setThresholdA(super.build(input.getThresholdA(), metaData
                .getThresholdA()));
        input.setTotalIncome(super.build(input.getTotalIncome(), metaData
                .getTotalIncome()));
        input.setTotalNumberOfDependents(super.build(input
                .getTotalNumberOfDependents(), metaData
                .getTotalNumberOfDependents()));
        input.setType(this.buildType(input.getType(), metaData.getType())); 
        input.setIvmConversionDate(super.build(input
                .getIvmConversionDate(), metaData
                .getIVMConversionDate()));
        input.setPg8RelaxationIndicator(super.build(input
                .getPg8RelaxationIndicator(), metaData
                .getPg8RelaxationIndicator()));
        input.setWorkflowCaseStatus(this.buildWorkflowCaseStatus(input.getWorkflowCaseStatus(), metaData.getIvmCaseStatus()));
        // ES_4.2_CodeCR13221_CR_VistA to Send BTFI to ES - and - ES to Send BTFI to VistA 
        input.setBtFinancialInd(super.build(input.getBtFinancialInd(), metaData.getBtFinancialInd()));

        this.buildStatuses(input, metaData.getStatuses());
        
        //If the primary test type is MT and No RxCopy status is uploaded, get the Exceptiom status from ZPD
        if (input.getType() != null && 
                IncomeTestType.CODE_MEANS_TEST.getCode().equals(input.getType().getCode())){
            IncomeTestStatus mtStatus = input.getIncomeTestStatus(); 
            if(mtStatus != null){
                //Get Rx Copy status
                if (input.getPharmacyCoPayStatus() == null && 
                        StringUtils.isNotEmpty(metaData.getRxCopayExemptionStatus())){
                    //build rx copy status and add to the income test statuses
                    IncomeTestStatus rxCopyStatus = new IncomeTestStatus ();
                    rxCopyStatus.setCompletedDate(mtStatus.getCompletedDate());
                    rxCopyStatus.setLastEditedDate(mtStatus.getLastEditedDate());
                    rxCopyStatus.setStatus(this.buildMeansTestStatus(rxCopyStatus.getStatus(),
                        metaData.getRxCopayExemptionStatus()));
                    rxCopyStatus.setType(this.buildType(rxCopyStatus.getType(),
                        IncomeTestType.CODE_CO_PAY_EXEMPTION_TEST.getCode()));
                    rxCopyStatus.setDeterminedStatus(rxCopyStatus.getStatus());
                    input.addStatus(rxCopyStatus);
                }
            }
        }
    }

	public Builder getwfCaseStatusBuilder() {
		return wfCaseStatusBuilder;
	}

	public void setwfCaseStatusBuilder(Builder workflowCaseStatusBuuilder) {
		this.wfCaseStatusBuilder = workflowCaseStatusBuuilder;
	}
}