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

//Java Classes
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

//Framework classes
import gov.va.med.fw.hl7.InvalidMessageException;
import gov.va.med.fw.hl7.InvalidSegmentException;
import gov.va.med.fw.hl7.Message;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;
import gov.va.med.fw.hl7.builder.HL7MetaData;
import gov.va.med.fw.hl7.segment.PID;
import gov.va.med.fw.hl7.segment.RF1;
import gov.va.med.fw.hl7.segment.ZCT;
import gov.va.med.fw.model.EntityKey;

//ESR Classes
import gov.va.med.esr.messaging.constants.HL7Constants;
import gov.va.med.esr.service.trigger.PersonTriggerEvent;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.messaging.SiteIdentity;

/**
 * Class to build the ORUZ05 message from a person object.
 * 
 * @author Alex Yoon
 * @version 1.0
 */
public class ORUZ05Builder extends AbstractMessageBuilder
{
    /**
    * An instance of serialVersionUID 
    */
   private static final long serialVersionUID = -1594567116686886726L;

   private Builder pidBuilder; 

    private ZPDZ05Builder zpdBuilder;

    private ZGDZ05Builder zgdBuilder;

    private RF1Z05Builder rf1Builder;

    private ZTAZ05Builder ztaBuilder;
    
    private ZCTBuilder zctBuilder;
    
    private ZEMBuilder zemBuilder;

	/**
     * Default constructor
     */
    public ORUZ05Builder()
    {
        super();
    }

    /**
     * @return Returns the pidBuilder.
     */
    public Builder getPidBuilder()
    {
        return pidBuilder;
    }

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

    /**
     * @return Returns the zgdBuilder.
     */
    public ZGDZ05Builder getZgdBuilder()
    {
        return zgdBuilder;
    }

    /**
     * @param zgdBuilder
     *            The zgdBuilder to set.
     */
    public void setZgdBuilder(ZGDZ05Builder zgdBuilder)
    {
        this.zgdBuilder = zgdBuilder;
    }

    /**
     * @return Returns the zpdBuilder.
     */
    public ZPDZ05Builder getZpdBuilder()
    {
        return zpdBuilder;
    }

    /**
     * @param zpdBuilder
     *            The zpdBuilder to set.
     */
    public void setZpdBuilder(ZPDZ05Builder zpdBuilder)
    {
        this.zpdBuilder = zpdBuilder;
    }

    /**
     * @param rf1Builder
     *            The rf1Builder to set.
     */
    public void setRf1Builder(RF1Z05Builder rf1Builder)
    {
        this.rf1Builder = rf1Builder;
    }

  
    public ZTAZ05Builder getZtaBuilder() {
		return ztaBuilder;
	}

	public void setZtaBuilder(ZTAZ05Builder ztaBuilder) {
		this.ztaBuilder = ztaBuilder;
	}


	public ZCTBuilder getZctBuilder() {
		return zctBuilder;
	}

	public void setZctBuilder(ZCTBuilder zctBuilder) {
		this.zctBuilder = zctBuilder;
	}

	public ZEMBuilder getZemBuilder() {
		return zemBuilder;
	}

	public void setZemBuilder(ZEMBuilder zemBuilder) {
		this.zemBuilder = zemBuilder;
	}
	
    /**
     * Method to build the ORUZ05 message.
     * 
     * @param object
     *            array The person who is source of message content.
     * @param siteIdentity
     *            The siteIdentity that is a destination of message.
     * @return The ORUZ05 message.
     * @throws BuilderException
     */
    public Message build(Object[] args) throws BuilderException
    {
        return this.build((Person) args[0], (SiteIdentity) args[1],
                (args[2] == null?null:(EntityKey) args[2]),
                (args[3] == null?null:(PersonTriggerEvent) args[3]) );
    }

    /**
     * Method to build the ORUZ05 message.
     * 
     * @param The
     *            person who is source of message content.
     * @param siteIdentity
     *            The siteIdentity that is a destination of message.
     * @param entityKey
     * 	The calling service may want to build the message for a particular EntityKey. 
     * 	e.g if the message is being built for Dependents, the Entity key indicates 
     * 	the specific Dependent for which the message needs to be built. 
     *  
     * @param triggerEvent
     * 	Rules will trigger  
     * @return The ORUZ05 message.
     * @throws BuilderException
     */
    public Message build(Person person, SiteIdentity siteIdentity,
            EntityKey entityKey, PersonTriggerEvent triggerEvent)
            throws BuilderException
    {
        if (person == null || siteIdentity == null )
        {
            throw new BuilderException(
                    "Invalid input parameters to build an object");
        }        
        
  
        Message message = null;
        List segments = new ArrayList();

        try
        {
            HL7MetaData metaData = new HL7MetaData(person);

            segments.add(super.buildMSHSegment(siteIdentity,
                    HL7Constants.ORUZ05));
 
            PIDMetaData pidMetaData = new PIDMetaData(person);
            pidMetaData.setSiteIdentity(siteIdentity);
            
            //No need to pass the EntityKey as PID will always build the 
            //permanent/correspondence address from the list of addresses of the Person
            segments.add(((PIDZ05Builder)pidBuilder).build(pidMetaData, triggerEvent));
            segments.add(zpdBuilder.build(metaData, triggerEvent));
            segments.add(ztaBuilder.build(metaData, triggerEvent));
            //CCR 9712: move ZGD here
            segments.add(zgdBuilder.build(metaData, entityKey, triggerEvent ));

            //CCR9932 Outbound Z05 does not include multiple ZCT segments for each contact
            List zctSegments = (List) zctBuilder.build(metaData, triggerEvent);
            
            //There will be at least one ZCT segment. So no null check needed
            for (Iterator iter = zctSegments.iterator(); iter.hasNext();)
            {
                ZCT zct = (ZCT) iter.next();
                segments.add(zct);    
            }
            
            // ESR3.1 CCR9857 Spouse Employment Info/Address not on ZEM in Z05
            // Return person as well as spouse's employment data
            // Build ZCD segments - repeatable
            List zemSegments = (List)this.zemBuilder.build(metaData, triggerEvent);
            for( int i = 0; i < zemSegments.size(); i++ ) {
               segments.add(zemSegments.get(i));
            }
            
            List rf1Segments = (List)rf1Builder.build(metaData, triggerEvent);
            
            //There will be at least one RF1 segment. So no null check needed
            for (Iterator iter = rf1Segments.iterator(); iter.hasNext();)
            {
                RF1 rf1 = (RF1) iter.next();
                segments.add(rf1);    
            }

            message = new Message(segments, HL7Constants.ORUZ05,true);

        } catch (InvalidSegmentException me)
        {
            throw new BuilderException(
                    "Failed to build ORUZ05 message due to an segment exception ",
                    me);
        } catch (InvalidMessageException me)
        {
            throw new BuilderException(
                    "Failed to build ORUZ05 message due to an exception ", me);
        }
 
        if(super.logger.isDebugEnabled())
        {
            super.logger.info("ORUZ05 Message = " + message.getMessageData()); 
        }
        return message;
    }

    /**
     * Method to build the PID segment.
     * 
     * @param person
     *            The person object that is source of message content.
     * @param siteIdentity
     *            The unique identifier for this site.
     * @return The PID segment.
     * @throws BuilderException
     */
    protected PID buildPIDSegment(Person person, SiteIdentity siteIdentity)
            throws BuilderException
    {
        PID segment = null;

        try
        {
            PIDMetaData metaData = new PIDMetaData(person);
            metaData.setSiteIdentity(siteIdentity);

            //Get segment through its builder
            segment = (PID) (this.pidBuilder.build(metaData));
        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build PID Segment due to an exception ", e);
        }

        return segment;
    }

}