/********************************************************************
 * 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;


// Library Classes

// Framework Classes
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

// Common Classes
import gov.va.med.esr.common.model.ee.ConflictExperience;
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.lookup.FilipinoVeteranProof;
import gov.va.med.esr.common.model.lookup.ServicePeriod;

// 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 MilitaryServiceBuilder extends EntityBuilder
{

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

	private Builder conflictExperienceBuilder;

    private Builder serviceEpisodeBuilder;

    private Builder servicePeriodBuilder;

    private Builder filipinoVeteranProofBuilder;

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

    public Builder getConflictExperienceBuilder()
    {
        return this.conflictExperienceBuilder;
    }

    public void setConflictExperienceBuilder(Builder conflictExperienceBuilder)
    {
        this.conflictExperienceBuilder = conflictExperienceBuilder;
    }

    public Builder getServiceEpisodeBuilder()
    {
        return this.serviceEpisodeBuilder;
    }

    public void setServiceEpisodeBuilder(Builder serviceEpisodeBuilder)
    {
        this.serviceEpisodeBuilder = serviceEpisodeBuilder;
    }

    public Builder getServicePeriodBuilder()
    {
        return this.servicePeriodBuilder;
    }

    public void setServicePeriodBuilder(Builder servicePeriodBuilder)
    {
        this.servicePeriodBuilder = servicePeriodBuilder;
    }

    /**
     * @return Returns the filipinoVeteranProofBuilder.
     */
    public Builder getFilipinoVeteranProofBuilder()
    {
        return filipinoVeteranProofBuilder;
    }

    /**
     * @param filipinoVeteranProofBuilder
     *            The filipinoVeteranProofBuilder to set.
     */
    public void setFilipinoVeteranProofBuilder(
            Builder filipinoVeteranProofBuilder)
    {
        this.filipinoVeteranProofBuilder = filipinoVeteranProofBuilder;
    }

    public MilitaryService build(MilitaryServiceMetaData metaData)
            throws BuilderException
    {
        MilitaryService input = metaData.getEntity();
        MilitaryService output = (input == null) ? new MilitaryService()
                : input;

        this.transfer(output, metaData);

        return this.shouldKeep(output) ? output : null;
    }

    private ConflictExperience buildConflictExperience(
            ConflictExperience input, ConflictExperienceMetaData metaData)
            throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        } else
        {
            metaData.setEntity(input);
            return (ConflictExperience) this.conflictExperienceBuilder
                    .build(metaData);
        }
    }

    /**
     * Create ConflictExperiences from MetaData
     * 
     * @param input
     * @param militaryServiceSiteRecordMetaData
     * @throws BuilderException
     */
    private void buildConflictExperiences(MilitaryServiceSiteRecord input,
            MilitaryServiceSiteRecordMetaData militaryServiceSiteRecordMetaData)
            throws BuilderException
    {
        ConflictExperienceMetaData[] metaData = militaryServiceSiteRecordMetaData
                .getConflictExperiences();

        Set toAdd = new HashSet();

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

        for (Iterator i = toAdd.iterator(); i.hasNext();)
        {
            input.addConflictExperience((ConflictExperience) i.next());
        }
    }


    private MilitaryServiceEpisode buildServiceEpisode(
            MilitaryServiceEpisode input,
            MilitaryServiceEpisodeMetaData metaData) throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        } else
        {
            metaData.setEntity(input);
            return (MilitaryServiceEpisode) this.serviceEpisodeBuilder
                    .build(metaData);
        }
    }

    private void buildMilitaryServiceEpisodes(MilitaryServiceSiteRecord input,
            MilitaryServiceSiteRecordMetaData militaryServiceSiteRecordMetaData)
            throws BuilderException
    {
        MilitaryServiceEpisodeMetaData[] metaData = militaryServiceSiteRecordMetaData
                .getMilitaryServiceEpisodes();
        Set toAdd = new HashSet();
        Set toRemove = new HashSet(input.getMilitaryServiceEpisodes());

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

        for (Iterator i = toRemove.iterator(); i.hasNext();)
        {
            input.removeMilitaryServiceEpisode((MilitaryServiceEpisode) i
                    .next());
        }

        for (Iterator i = toAdd.iterator(); i.hasNext();)
        {
            input.addMilitaryServiceEpisode((MilitaryServiceEpisode) i.next());
        }
    }

    private ServicePeriod buildServicePeriod(ServicePeriod input, String code)
            throws BuilderException
    {
        return super.shouldDelete(code) ? null : (ServicePeriod) super.build(
                this.servicePeriodBuilder, input, code);
    }

    private boolean shouldKeep(MilitaryService obj)
    {
        return true;
    }

    private void processConflictExperience(Set toAdd,
            ConflictExperienceMetaData metaData) throws BuilderException
    {
        ConflictExperience value = this.buildConflictExperience(null, metaData);
        //Add the Conflict experience only if the Service indicator is "Y".
        //Do not add it for "N" or "U"
        if (value != null)
        {
            Boolean shouldAdd = super.build(new Boolean(value != null),
                    metaData.getIndicator());
            if (Boolean.TRUE.equals(shouldAdd))
            { 
                    toAdd.add(value);
            }
        }
    }

    private void processServiceEpisode(Set toAdd,
            MilitaryServiceEpisodeMetaData metaData) throws BuilderException
    {
        MilitaryServiceEpisode value = this.buildServiceEpisode(null, metaData);
        if (value != null)
        {
            toAdd.add(value);
        }
    }

    private void transfer(MilitaryService input,
            MilitaryServiceMetaData metaData) throws BuilderException
    {

        input.setCombatVeteranEligibilityEndDate(super.build(input
                .getCombatVeteranEligibilityEndDate(), metaData
                .getCombatVeteranEligibilityEndDate()));
        input.setDisabilityRetirementIndicator(super.build(input
                        .getDisabilityRetirementIndicator(), metaData
                        .getDisabilityRetirementStatus()));
        input.setDischargeDueToDisability(super.build(input
                .getDischargeDueToDisability(), metaData
                .getDischargeDueToDisability()));

        //Add a SiteRecord for the site in the metadata
        this.buildMilitaryServiceSiteRecords(input, metaData
                .getMilitaryServiceSiteRecord());

    }

    /**
     * Create ConflictExperiences from MetaData
     * 
     * @param input
     * @param militaryServiceSiteRecordMetaData
     * @throws BuilderException
     */
    private void buildMilitaryServiceSiteRecords(MilitaryService input,
            MilitaryServiceSiteRecordMetaData militaryServiceSiteRecordMetaData)
            throws BuilderException
    {

        Set toAdd = new HashSet();

        this.processMilitaryServiceSiteRecord(toAdd, 
                militaryServiceSiteRecordMetaData);

        //remove all MilitaryServiceSiteRecords and build the one from message
        input.removeAllMilitaryServiceSiteRecords();
        
        for (Iterator i = toAdd.iterator(); i.hasNext();)
        {
            input.addMilitaryServiceSiteRecord((MilitaryServiceSiteRecord) i
                    .next());
        }
    }

    private void processMilitaryServiceSiteRecord(Set toAdd,
             MilitaryServiceSiteRecordMetaData metaData)
            throws BuilderException
    {
        MilitaryServiceSiteRecord value = this.buildMilitaryServiceSiteRecord(
                null, metaData);
        
        if (value != null)
        {
            toAdd.add(value);
        }
    }

    /**
     * @param militaryServiceSiteRecordsBySite
     * @param metaData
     * @return
     * @throws BuilderException
     */

    private MilitaryServiceSiteRecord buildMilitaryServiceSiteRecord(
            MilitaryServiceSiteRecord input,
            MilitaryServiceSiteRecordMetaData metaData) throws BuilderException
    {
        if (metaData == null)
        {
            return null;
        }
        if (input == null)
        {
            input = new MilitaryServiceSiteRecord();
        }
        metaData.setEntity(input);

        input.setSite(build(input.getSite(), metaData.getSite()));
        input.setServicePeriod(this.buildServicePeriod(
                input.getServicePeriod(), metaData.getServicePeriod()));

        input.setFilipinoVeteranProof(
                buildFilipinoVeteranProof(
                        input.getFilipinoVeteranProof(), 
                        metaData.getFilipinoVeteranProof()));
        
        buildConflictExperiences(input, metaData);
        buildMilitaryServiceEpisodes(input, metaData);

        return input; 

    }

    private FilipinoVeteranProof buildFilipinoVeteranProof(
            FilipinoVeteranProof input, String code) throws BuilderException
    {
        return super.shouldDelete(code) ? null : (FilipinoVeteranProof) super
                .build(this.filipinoVeteranProofBuilder, input, code);
    }

}