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

//Java Classes
import java.util.Calendar;
import java.util.Date;

import gov.va.med.fw.hl7.segment.MSA;
import gov.va.med.fw.hl7.segment.MSH;
import gov.va.med.fw.hl7.segment.PID;
import gov.va.med.fw.hl7.segment.QRD;
import gov.va.med.fw.hl7.segment.QRF;
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.util.builder.AbstractBuilder;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.messaging.constants.HL7Constants;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.MessagingService;

//MSDS Seeding changes

import gov.va.med.fw.hl7.segment.QPD;
import gov.va.med.fw.hl7.segment.RCP;

/**
 * Abstract class that should be extended by outbound message builders.
 * 
 * @author Alex Yoon
 * @version 1.0
 */
public abstract class AbstractMessageBuilder extends AbstractBuilder
{

    private static final long serialVersionUID = -1370346746640850300L; 
    private BHSBuilder bhsBuilder;
	
	private BTSBuilder btsBuilder;     

	private QRDBuilder qrdBuilder;

    private QRFBuilder qrfBuilder;

    private MSABuilder msaBuilder;

    private MSHBuilder mshBuilder;

    private MessagingService messagingService;

    private LookupService lookupService;

    private Builder pidBuilder;
    
    //MSDS Seeding Changes
    
    private QPDBuilder qpdBuilder;
    
    private RCPBuilder rcpBuilder;

    /**
     * Default constructor
     */
    protected AbstractMessageBuilder()
    {
        super();
    }
    
    /**
     * @return Returns the bhsBuilder.
     */
    public BHSBuilder getBhsBuilder()
    {
        return bhsBuilder;
    }
    /**
     * @param bhsBuilder The bhsBuilder to set.
     */
    public void setBhsBuilder(BHSBuilder bhsBuilder)
    {
        this.bhsBuilder = bhsBuilder;
    }
    /**
     * @return Returns the btsBuilder.
     */
    public BTSBuilder getBtsBuilder()
    {
        return btsBuilder;
    }
    /**
     * @param btsBuilder The btsBuilder to set.
     */
    public void setBtsBuilder(BTSBuilder btsBuilder)
    {
        this.btsBuilder = btsBuilder;
    }
    /**
     * @return Returns the qrdBuilder.
     */
    public QRDBuilder getQrdBuilder()
    {
        return qrdBuilder;
    }

    /**
     * @param qrdBuilder
     *            The qrdBuilder to set.
     */
    public void setQrdBuilder(QRDBuilder qrdBuilder)
    {
        this.qrdBuilder = qrdBuilder;
    }

    /**
     * @return Returns the qrfBuilder.
     */
    public QRFBuilder getQrfBuilder()
    {
        return qrfBuilder;
    }

    /**
     * @param qrfBuilder
     *            The qrfBuilder to set.
     */
    public void setQrfBuilder(QRFBuilder qrfBuilder)
    {
        this.qrfBuilder = qrfBuilder;
    }

    /**
     * @return Returns the msaBuilder.
     */
    public MSABuilder getMsaBuilder()
    {
        return msaBuilder;
    }

    /**
     * @param msaBuilder
     *            The msaBuilder to set.
     */
    public void setMsaBuilder(MSABuilder msaBuilder)
    {
        this.msaBuilder = msaBuilder;
    }

    public MSHBuilder getMshBuilder()
    {
        return this.mshBuilder;
    }

    public void setMshBuilder(MSHBuilder mshBuilder)
    {
        this.mshBuilder = mshBuilder;
    }

    public MessagingService getMessagingService()
    {
        return this.messagingService;
    }

    public void setMessagingService(MessagingService messagingService)
    {
        this.messagingService = messagingService;
    }

    /**
     * @return Returns the lookupService.
     */
    public LookupService getLookupService()
    {
        return lookupService;
    }

    /**
     * @param lookupService
     *            The lookupService to set.
     */
    public void setLookupService(LookupService lookupService)
    {
        this.lookupService = lookupService;
    }

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

    /**
     * @param pidbuilder
     *            The pidbuilder to set.
     */
    public void setPidBuilder(Builder pidbuilder)
    {
        this.pidBuilder = pidbuilder;
    }
    
    //MSDS Seeding Changes
    
    /**
     * @return Returns the qpdBuilder.
     */
    public QPDBuilder getQpdBuilder() {
        return qpdBuilder;
    }
    
    /**
     * @param qpdBuilder
     *            The qpdBuilder to set.
     */
    public void setQpdBuilder(QPDBuilder qpdBuilder) {
        this.qpdBuilder = qpdBuilder;
    }
    
    /**
     * @return Returns the rcpBuilder.
     */
    public RCPBuilder getRcpBuilder() {
        return rcpBuilder;
    } 
    
    /**
     * @param rcpBuilder
     *            The rcpBuilder to set.
     */
    public void setRcpBuilder(RCPBuilder rcpBuilder) {
        this.rcpBuilder = rcpBuilder;
    }

    /**
     * Method to build MSH segment.
     * 
     * @param siteIdentity
     *            The siteIdentity that is a destination of message.
     * @return The MSH segment.
     * @throws BuilderException
     */
    protected MSH buildMSHSegment(SiteIdentity site, String messageType)
            throws BuilderException
    {
        if (site == null)
        {
            throw new BuilderException(
                    "Invalid input parameter to build a segment");
        }

        return this.buildMSHSegment(site.getVaFacility(), messageType);
    }

    /**
     * Method to build MSH segment.
     * 
     * @param VAFacility
     *            The VAFacility that is a destination of message.
     * @return The MSH segment.
     * @throws BuilderException
     */
    protected MSH buildMSHSegment(VAFacility site, String messageType)
            throws BuilderException
    {
        MSH segment = null;

        try
        {
            MSHMetaData metaData = new MSHMetaData((AbstractEntity) null);
            Date creationDatetime = Calendar.getInstance().getTime();

            String id = this.messagingService.generateControlIdentifier();

            String receiving_facility = site.getStationNumber();
            String receiving_application = "VAMC " + receiving_facility;

            metaData
                    .setApplicationACKType(HL7Constants.APPLICATION_ACK_TYPE_AL);
            metaData.setControlID(id);
            metaData.setCreationDatetime(creationDatetime);
            metaData.setMessageType(messageType);
            metaData.setReceivingApplication(receiving_application);
            metaData.setReceivingFacility(receiving_facility);

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

        return segment;
    }

    /**
     * Method to create MSA segment from data in a message.
     * 
     * @param ackType
     *            The type of acknowledgement.
     * @param controlID
     *            The identifier for the message.
     * @param errorText
     *            The error text related to the error.
     * @return The MSA segment
     * @throws BuilderException
     */
    protected MSA buildMSASegment(String ackType, String referenceMessageID, String errorMessage)
            throws BuilderException
    {
        MSA segment = null;

        try
        {
            MSAMetaData metaData = new MSAMetaData((AbstractEntity) null);

            metaData.setACKCode(ackType);
            metaData.setControlID(referenceMessageID);
            metaData.setTextMessage(errorMessage);

            segment = (MSA) (this.msaBuilder.build(metaData));
        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build MSA Segment due to an exception ", e);
        }

        return segment;
    }
    
        

    /**
     * Method to build the QRD segment.
     * QRD segment has 
     * 
     * @param person
     *            The person who is source for QRD segment content.
     * @return The QRD segment.
     * @throws BuilderException
     */

    protected QRD buildQRDSegment(Person person, String queryId, String whoSubjectFilter,
            Date queryDateTime, String whatSubjectFilter,
            String whatDepartmentCode) throws BuilderException
    {
        QRD segment = null;

        try
        {
            QRDMetaData metaData = new QRDMetaData(person);

            metaData.setQueryDateTime(DateFormatter.formatDate(queryDateTime,
                    DateFormatter.DATETIME_ZONE_FORMAT));
            metaData.setQueryId(queryId);
            metaData.setWhoSubjectFilter(whoSubjectFilter);
            metaData.setWhatSubjectFilter(whatSubjectFilter);
            metaData.setWhatDepartmentCode(whatDepartmentCode);

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

        return segment;
    }

    /**
     * Method to build the QRF segment. Builds a QRF with WhatUserQualifier =
     * Birth date and OtherQuerySubjectFilter = Gender
     * 
     * @param person
     *            The person who is source for QRF segment content.
     * @return The QRF segment.
     * @throws BuilderException
     */
    protected QRF buildQRFSegment(Person person) throws BuilderException
    {
        QRF segment = null;

        String birthDate = person.getBirthRecord() == null ? null
                : DateFormatter.formatDate(person.getBirthRecord()
                        .getBirthDate());
        String gender = person.getGender() == null ? null : person.getGender()
                .getCode();

        segment = buildQRFSegment(person,
                HL7Constants.WHERE_SUBJECT_FILTER_IVM, birthDate, gender);

        return segment;
    }

    protected QRF buildQRFSegment(Person person, String whereSubjectFilter,
            String whatUserQualifier, String otherSubjectQueryFilter)
            throws BuilderException
    {
        QRF segment = null;

        try
        {
            QRFMetaData metaData = new QRFMetaData(person);
            metaData.setWhereSubjectFilter(whereSubjectFilter);
            //Date of Birth
            metaData.setWhatUserQualifier(whatUserQualifier);

            //Gender
            metaData.setOtherQuerySubjectFilter(otherSubjectQueryFilter);

            //Get segment through its builder
            segment = (QRF) (this.qrfBuilder.build(metaData));

        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build QRF Segment due to an exception ", e);
        }

        return segment;
    }

    /**
     * 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) (pidBuilder.build(metaData));
        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build PID Segment due to an exception ", e);
        }

        return segment;
    }
    
    //MSDS Seeding Changes
    
    /**
     * Method to build the QPD segment.
     * QPD segment has 
     * 
     * @param person
     *            The person who is source for QPD segment content.
     * @return The QPD segment.
     * @throws BuilderException
     */

    protected QPD buildQPDSegment(Person person, String dfn, String eventType) throws BuilderException
    {
        QPD segment = null;

        try
        {
            QPDMetaData metaData = new QPDMetaData(person);

            //metaData.setId("QPD");
            metaData.setComment("Get MSDS data");
            metaData.setEventType(eventType);
            metaData.setDfn(dfn);
            
            //Get segment through its builder
            segment = (QPD) (this.qpdBuilder.build(metaData));
        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build QPD Segment due to an exception ", e);
        }

        return segment;
    }
    
    /**
     * Method to build the RCP segment. Builds a RCP with empty content
     * 
     * @param person
     *            The person who is source for RCP segment content.
     * 
     * @return The RCP segment.
     * @throws BuilderException
     */
    protected RCP buildRCPSegment(AbstractEntity abstractEntity) throws BuilderException
    {
        RCP segment = null;

        try
        {
            RCPMetaData metaData = new RCPMetaData(abstractEntity);
            //metaData.setId("RCP");
            metaData.setResponseDetail("");

            //Get segment through its builder
            segment = (RCP) (this.rcpBuilder.build(metaData));

        } catch (Exception e)
        {
            throw new BuilderException(
                    "Failed to build RCP Segment due to an exception ", e);
        }

        return segment;
    }

}