

package gov.va.med.cds.testharness.vhim400.builders;


import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Random;

import org.apache.logging.log4j.Logger;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;


public class OutpatientMedicationPromiseBuilder
    extends
        AbstractEntryPointBuilder
{
    private static int OUTPATIENT_MEDICATION_PROMISE_IDX = 10000;

    public static final String[] DATA_ENTERER_IDS = { "test_IDS_1", "test_IDS_2", "test_IDS_3" };
    public static final String[] PHARMACIST_IDS = { "test_IDS_6001", "test_IDS_6002", "test_IDS_6003" };
    public static final String[] FINISHER_IDS = { "test_FINISHERID_7001", "test_FINISHERID_7002", "test_FINISHERID_7003" };
    public static final String[] RESPONSIBLE_PHYSICIAN_IDS = { "test_IDS_9001", "test_IDS_9002", "test_IDS_9003" };
    public static final String[] RENEWER_IDS = { "test_IDS_10001", "test_IDS_10002", "test_IDS_10003" };
    public static final String[] VERIFYING_PHARMACIST_IDS = { "test_IDS_11001", "test_IDS_11002", "test_IDS_11003" };
    public static final String[] ATTENDING_PHYSICIAN_IDS = { "test_IDS_12001", "test_IDS_12002", "test_IDS_12003" };
    public static final String[] COSIGNER_IDS = { "test_IDS_13001", "test_IDS_13002", "test_IDS_13003" };
    public static final String[] FILLER_IDS = { "test_IDS_14001", "test_IDS_14002", "test_IDS_14003" };
    public static final String[] CANCELLER_IDS = { "test_IDS_15001", "test_IDS_15002", "test_IDS_15003" };
    public static final String[] CURRENTPROVIDER_IDS = { "test_PROVIDERD_7001", "test_PROVIDERID_7002", "test_PROVIDERID_7003" };
    public static final String[] INITIATOR_IDS = { "test_INITIATOR_17001", "test_INITIATOR_17002", "test_INITIATOR_17003" };


    public OutpatientMedicationPromiseBuilder( )
    {
        super();
    }


    public OutpatientMedicationPromiseBuilder( Random aRandom )
    {
        super( aRandom );
    }


    public Element makeInsertPharmacy( )
    {
        return makePharmacy();
    }


    public List<Element> makeInsertPharmacies( int count )
    {
        return makePharmacies( count );
    }


    public Element makePharmacy( )
    {
        return makePharmacy( null );
    }


    public Element makePharmacy( Element patientIdentifier )
    {
        Element pharmacy = createPharmacy( OUTPATIENT_MEDICATION_PROMISE_IDX++ , patientIdentifier );

        return pharmacy;
    }


    public Element createEntryPointRecord( Element personIdentifier )
    {
        return makePharmacy( personIdentifier );
    }


    public List<Element> makePharmacies( int number )
    {
        return makePharmacies( number, null );
    }


    public List<Element> makePharmacies( int number, Element personIdentifier )
    {
        List<Element> pharmacies = new ArrayList<Element>( number );
        for ( int i = 0; i < number; i++ )
        {
            pharmacies.add( makePharmacy( personIdentifier ) );
        }

        return pharmacies;
    }


    /**
     * Used to add more dispenses to a given pharmacy record; used in
     * integration test to prove that any number of dispenses records can be
     * added to a pharmacy record
     * 
     * @param outpatientMedicationPromise
     * @param dispenseType
     *            All(Refill and Partial)/Refill/Partial
     * @param dispenseRecordCount
     *            number of dispense records of given dispense type
     * @return pharmacy with new dispenses
     * @see EndToEndCRUADAutoWiredV400Test.createOutpatientMedicationPromiseWithSpecificDispensesXml
     */
    public Element makePharmacyWithDispenses( Element outpatientMedicationPromise, String dispenseType, int dispenseRecordCount )
    {
        createDispenses( outpatientMedicationPromise, OUTPATIENT_MEDICATION_PROMISE_IDX++ , dispenseType, dispenseRecordCount );
        return outpatientMedicationPromise;
    } 
    
    
    public List<Element> makeDispensesElementsForPharmacy(String dispenseType, int dispenseRecordCount )
    {
        List<Element> dispenseElements = new ArrayList<Element>();
        if ( dispenseType.equalsIgnoreCase( "All" ) )
        {

            dispenseElements.add( createOutpatientMedicationDispense( "originalDispense", "Original", dispenseRecordCount ) );
            
            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                dispenseElements.add( createOutpatientMedicationDispense( "refillDispense", "Refill", i ) );
            }

            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                dispenseElements.add( createOutpatientMedicationDispense( "partialDispense", "Partial", i ) );
            }
        }
        else
        {
            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                dispenseElements.add( createOutpatientMedicationDispense( getDispenseElementName( dispenseType ), dispenseType, i ) );
            }
        }
        return dispenseElements;
    }     
    
   
    

    /**
     * Used to add CurrentProviderComments to a given pharmacy record; used in
     * integration test to prove this CLOB datatype can store more than 4k data.
     * 
     * @param aOutpatientMedicationPromise
     * @param dispenseType
     *            All(Refill and Partial)/Refill/Partial
     * @param dispenseRecordCount
     *            number of dispense records of given dispense type
     * @return pharmacy with new dispenses
     * @see EndToEndCRUADAutoWiredV400Test.createOutpatientMedicationPromiseWithSpecificDispensesXml
     */
//    public Element makePharmacyWithCurrentProviderComments( Element outpatientMedicationPromise, String comment )
//    {
//        Element newCurrentProvider = createPractitionerLite( "currentProvider", CURRENTPROVIDER_IDS );
//        Element originalDispense = outpatientMedicationPromise.element( "originalDispense" );
//        originalDispense.add( newCurrentProvider );
//        originalDispense.add( createComment( "currentProviderComments", comment ) );
//        return outpatientMedicationPromise;
//    }

    public Element makeCurrentProviderForPharmacy()
    {
        return createPractitionerLite( "currentProvider", CURRENTPROVIDER_IDS );
    }    

    public Element makeCurrentProviderCommentsForPharmacy(String comment)
    {
        return createComment( "currentProviderComments", comment ) ;
    }    
    
    
    public Element makeCancelDateElementForPharmacy( int cancelDateYearOffset )
    {
        GregorianCalendar sysDate = null;
        Date cancelDt = null;

        if ( cancelDateYearOffset != 0 )
        {
            sysDate = new GregorianCalendar();
            sysDate.add( Calendar.YEAR, cancelDateYearOffset );// If expireYear is
            // -2 and if
            // sysdate is
            // 2008-01-01
            // then newYear
            // would be 2006
            cancelDt = sysDate.getTime();
        }        
        return createCancelAct( "cancel", cancelDt );
    }

    public Element makeExpiryDateElementForPharmacy(int expireDateYearOffset )
    {
        GregorianCalendar sysDate = null;
        Date expireDt = null;

        if ( expireDateYearOffset != 0 )
        {
            sysDate = new GregorianCalendar();
            sysDate.add( Calendar.YEAR, expireDateYearOffset );// If expireYear is
            // -2 and if
            // sysdate is
            // 2008-01-01
            // then newYear
            // would be 2006
            expireDt = sysDate.getTime();
        }        
        return createPointInTime( "expirationDate", expireDt );
    }    
    
    
//    public Element makePharmacyWithCancelDateNExpiryDate( Element pharmacy, int cancelDateYearOffset, int expireDateYearOffset )
//    {
//        GregorianCalendar sysDate = null;
//        Date cancelDt = null;
//        Date expireDt = null;
//
//        if ( expireDateYearOffset != 0 )
//        {
//            sysDate = new GregorianCalendar();
//            sysDate.add( Calendar.YEAR, expireDateYearOffset );// If expireYear is
//            // -2 and if
//            // sysdate is
//            // 2008-01-01
//            // then newYear
//            // would be 2006
//            expireDt = sysDate.getTime();
//            pharmacy.add( createPointInTime( "expirationDate", expireDt ) );
//        }
//
//        if ( cancelDateYearOffset != 0 )
//        {
//            sysDate = new GregorianCalendar();
//            sysDate.add( Calendar.YEAR, cancelDateYearOffset );// If cancelYear is
//            // 1 and if
//            // sysdate is
//            // 2008-01-01
//            // then newYear
//            // would be 2009
//            cancelDt = sysDate.getTime();
//            Element cancelAct = createCancelAct( "cancel", cancelDt );
//            pharmacy.add( cancelAct );
//        }
//
//        return pharmacy;
//    }


    private Element createPharmacy( int id, Element personIdentifier )
    {
        Element outpatientMedicationPromise = DocumentHelper.createElement( "outpatientMedicationPromises" );

        setOutpatientMedicationPromiseValues( outpatientMedicationPromise, id, personIdentifier );

        return outpatientMedicationPromise;
    }


    /**
     * Adds dispense records to a pharamcy records.
     * 
     * @param outpatientMedicationPromise
     * @param id
     * @param dispenseType
     *            All(Original/Refill and Partial - Adds all including Original
     *            dispense if it does not exist else adds only Refill and
     *            Partial)/Refill/Partial
     * @param dispenseRecordCount
     *            number of dispense records
     * @see makePharmacyWithDispenses() and setPharmacyValues()
     */
    private void createDispenses( Element outpatientMedicationPromise, int id, String dispenseType, int dispenseRecordCount )
    {
        if ( dispenseType.equalsIgnoreCase( "All" ) )
        {
            if ( outpatientMedicationPromise.element( "originalDispense" ) == null )
            {
                outpatientMedicationPromise.add( createOutpatientMedicationDispense( "originalDispense", "Original", id ) );
            }
            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                outpatientMedicationPromise.add( createOutpatientMedicationDispense( "refillDispense", "Refill", id ) );
            }
            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                outpatientMedicationPromise.add( createOutpatientMedicationDispense( "partialDispense", "Partial", id ) );
            }
        }
        else
        {
            for ( int i = 0; i < dispenseRecordCount; i++ )
            {
                outpatientMedicationPromise.add( createOutpatientMedicationDispense( getDispenseElementName( dispenseType ), dispenseType, id ) );
            }
        }
    }


    private String getDispenseElementName( String dispenseType )
    {
        if ( "Original".equals( dispenseType ) )
        {
            return "originalDispense";
        }
        else if ( "Refill".equals( dispenseType ) )
        {
            return "refillDispense";
        }
        else if ( "Partial".equals( dispenseType ) )
        {
            return "partialDispense";
        }
        else
        {
            throw new IllegalArgumentException( String.format( "Invalid method parameter. Dispense type of '%s' is not valid.", dispenseType ) );
        }
    }


    /*
     <xsd:complexType name="OutpatientMedicationPromise">
    	<xsd:complexContent>
    		<xsd:extension base="pharmacy:MedicationPromise">
    			<xsd:sequence>
    				<xsd:element name="patient" type="common:PatientLite"/>
    				<xsd:element name="expirationDate" type="basedatatypes:PointInTime" minOccurs="0"/>
    				<xsd:element name="lastDispenseDate" type="basedatatypes:PointInTime" minOccurs="0"/>
    				<xsd:element name="numberOfRefillsAuthorized" type="xsd:int" minOccurs="0"/>
    				<xsd:element name="patientInstructions" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="otherPatientInstructions" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="expandedPatientInstructions" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="pharmacyInstructions" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="sig" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="digitalSignatureIndicator" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
    				<xsd:element name="copayTransactionType" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
    				<xsd:element name="transitionalRxBenefit" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
    				<xsd:element name="treatmentFactor" type="common:TreatmentFactor" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="originalDispense" type="pharmacy:OutpatientMedicationDispense" minOccurs="0"/>
    				<xsd:element name="refillDispense" type="pharmacy:OutpatientMedicationDispense" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="partialDispense" type="pharmacy:OutpatientMedicationDispense" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="cancel" type="pharmacy:CancelAct" minOccurs="0"/>
    				<xsd:element name="medicationInstructions" type="pharmacy:MedicationInstructionComponent" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="finisher" type="common:PractitionerParticipationLite" minOccurs="0"/>
    				<xsd:element name="activityLog" type="pharmacy:ActivityLog" minOccurs="0" maxOccurs="unbounded"/>
    				<xsd:element name="recordSource" type="basedatatypes:HL72FacilityIdentifier"/>
    				<xsd:element name="recordVersion" type="xsd:int"/>
    				<xsd:element name="recordUpdateTime" type="basedatatypes:PointInTime"/>
    			</xsd:sequence>
    		</xsd:extension>
    	</xsd:complexContent>
    </xsd:complexType>
     */
    @SuppressWarnings( "unchecked" )
    private void setOutpatientMedicationPromiseValues( Element outpatientMedicationPromise, int id, Element personIdentifier )
    {
        // MedicationPromise

        outpatientMedicationPromise.add( createHL72EntityIdentifier("recordIdentifier", id ));
        outpatientMedicationPromise.add( createSimpleStringElement( "pdtsPrescriptionId", "PdtsPrescriptionId" ) );
        outpatientMedicationPromise.add( createSimpleStringElement( "prescriptionId", "PrescriptionId" ) );
        outpatientMedicationPromise.add( createSimpleStringElement( "pharmacyPatientType", "PharmacyPatientType" ) );
        outpatientMedicationPromise.add( createSpecialDrugTracking( "specialDrugTracking", "SpecialDrugTracking" ) );
        outpatientMedicationPromise.add( createPractitionerParticipationLite( "dataEnterer", "DataEnterer", DATA_ENTERER_IDS ) );
        outpatientMedicationPromise.add( createPharmacyRequest( "pharmacyRequest" ) );

        Element newPatient = createPatientLite( "patient" );
        if ( personIdentifier != null )
        {
            newPatient.element( "identifier" ).element( "identity" ).setText( personIdentifier.elementText( "identity" ) );
            newPatient.element( "identifier" ).element( "assigningFacility" ).setText( personIdentifier.elementText( "assigningFacility" ) );
            newPatient.element( "identifier" ).element( "assigningAuthority" ).setText( personIdentifier.elementText( "assigningAuthority" ) );
        }
        outpatientMedicationPromise.add( newPatient );

        outpatientMedicationPromise.add( createPointInTime( "expirationDate" ) );
        outpatientMedicationPromise.add( createPointInTime( "lastDispenseDate" ) );
        outpatientMedicationPromise.add( createSimpleIntegerElement( "numberOfRefillsAuthorized", 2 ) );

        outpatientMedicationPromise.elements().addAll( createSimpleStringElements( "patientInstructions", "PatientInstructions", 2 ) );
        outpatientMedicationPromise.elements().addAll( createSimpleStringElements( "otherPatientInstructions", "OtherPatientInstructions", 2 ) );
        outpatientMedicationPromise.elements().addAll( createSimpleStringElements( "expandedPatientInstructions", "ExpandedPatientInstructions", 2 ) );
        outpatientMedicationPromise.elements().addAll( createSimpleStringElements( "pharmacyInstructions", "PharmacyInstructions", 2 ) );
        outpatientMedicationPromise.elements().addAll( createSimpleStringElements( "sig", "Sig", 2 ) );

        outpatientMedicationPromise.add( createHL72CodedElementLite( "digitalSignatureIndicator", "DigitalSignatureIndicator" ) );
        outpatientMedicationPromise.add( createHL72CodedElementLite( "copayTransactionType", "CopayTransactionType" ) );
        outpatientMedicationPromise.add( createHL72CodedElementLite( "transitionalRxBenefit", "TransitionalRxBenefit" ) );
        outpatientMedicationPromise.add( createTreatmentFactor( "treatmentFactor" ) );

        // create the dispense events for the oupatient medication dispense event.
        createDispenses( outpatientMedicationPromise, id, "All", 2 );

        outpatientMedicationPromise.add( createCancelAct( "cancel" ) );
        outpatientMedicationPromise.add( createMedicationInstructionComponent( "medicationInstructions" ) );
        outpatientMedicationPromise.add( createMedicationInstructionComponent( "medicationInstructions" ) );
        outpatientMedicationPromise.add( createPractitionerParticipationLite( "finisher", "Finisher Comment", FINISHER_IDS ) );
        outpatientMedicationPromise.add( createActivityLog( "activityLog" ) );
        outpatientMedicationPromise.add( createActivityLog( "activityLog" ) );
        outpatientMedicationPromise.add( createHL72FacilityIdentifier( "recordSource" ) );
        outpatientMedicationPromise.add( createSimpleIntegerElement( "recordVersion", id ) );
        outpatientMedicationPromise.add( createPointInTime( "recordUpdateTime" ) );
    }


    public void printPharmacies( List<Element> listOfResults )
    {
        printDomainRecords( listOfResults );
    }


    public void printPharmacies( List<Element> listOfResults, Logger logger )
    {
        printDomainRecords( listOfResults, logger );
    }


    protected void printPharmacy( Element outpatientMedicationPromise )
    {
        printDomainRecord( outpatientMedicationPromise );
    }


    protected void printPharmacy( Element outpatientMedicationPromise, Logger logger )
    {
        printDomainRecord( outpatientMedicationPromise, logger );
    }


    public String fillPrintBuffer( Object obj )
    {
        String returnString = "";

        if ( ( obj != null ) && ( obj instanceof Element ) )
        {
            returnString = ( ( Element )obj ).asXML();
        }

        return returnString;
    }


    /*
     * <xsd:complexType name="PharmacyRequest"> 
     * <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="cosigner" type="common:PractitionerParticipationLite"/> 
     *      <xsd:element minOccurs="0" name="orderedMedication" type="common:Medicine"/> 
     *      <xsd:element minOccurs="0" name="genericRequestIdentifier" type="basedatatypes:HL72EntityIdentifier"/> 
     *      <xsd:element minOccurs="0" name="orderLocationIdentifier" type="basedatatypes:HL72LocationIdentifier"/> 
     *      <xsd:element minOccurs="0" name="orderedItem" type="common:PharmacyOrderableItem"/> 
     *      <xsd:element minOccurs="0" name="orderingInstitutionIdentifier" type="basedatatypes:HL72OrganizationIdentifier"/> 
     *      <xsd:element minOccurs="0" name="orderDate" type="basedatatypes:PointInTime"/>
     *      <xsd:element minOccurs="0" name="status" type="xsd:string"/> 
     *      <xsd:element minOccurs="0" name="statusModifier" type="basedatatypes:HL72CodedElementLite"/> 
     *      </xsd:sequence>
     * </xsd:complexType>
     */
    private Element createPharmacyRequest( String elementName )
    {
        Element newPharmacyRequest = DocumentHelper.createElement( elementName );
        newPharmacyRequest.add( createPractitionerParticipationLite( "cosigner", "Cosigner", COSIGNER_IDS ) );
        newPharmacyRequest.add( createMedicine( "orderedMedication", "OrderedMedication" ) );
        newPharmacyRequest.add( createHL72EntityIdentifier( "genericRequestIdentifier" ) );
        newPharmacyRequest.add( createHL72LocationIdentifier( "orderLocationIdentifier" ) );
        newPharmacyRequest.add( createPharmacyOrderableItem( "orderedItem", "OrderedItem" ) );
        newPharmacyRequest.add( createHL72OrganizationIdentifier( "orderingInstitutionIdentifier" ) );
        newPharmacyRequest.add( createPointInTime( "orderDate" ) );
        newPharmacyRequest.add( createSimpleStringElement( "status", "Status" ) );
        newPharmacyRequest.add( createHL72CodedElementLite( "statusModifier", "StatusModifier" ) );

        return newPharmacyRequest;
    }


    /*
     * <xsd:complexType name="PharmacyOrderableItem"> 
     *  <xsd:sequence>
     *      <xsd:element minOccurs="0" name="itemCode" type="basedatatypes:HL72CodedElementLite"/> <xsd:element minOccurs="0" name="dosageFormCode" type="basedatatypes:HL72CodedElementLite"/>
     *  </xsd:sequence> 
     * </xsd:complexType>
     */
    private Element createPharmacyOrderableItem( String elementName, String type )
    {
        Element newPharmacyOrderableItem = DocumentHelper.createElement( elementName );
        newPharmacyOrderableItem.add( createHL72CodedElementLite( "itemCode", type + " Item" ) );
        newPharmacyOrderableItem.add( createHL72CodedElementLite( "dosageFormCode", "DosageForm" ) );

        return newPharmacyOrderableItem;
    }


    /*
     * <xsd:complexType name="SpecialDrugTracking"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="totalDailyDosage"type="basedatatypes:PhysicalQuantity"/> 
     *      <xsd:element minOccurs="0" name="wbcObservation" type="pharmacy:WbcObservation"/> 
     *  </xsd:sequence>
     * </xsd:complexType>
     */
    private Element createSpecialDrugTracking( String elementName, String type )
    {
        Element newSpecialDrugTracking = DocumentHelper.createElement( elementName );
        Element newTotalDailyDosage = createPhysicalQuantity( "totalDailyDosage" );
        newSpecialDrugTracking.add( newTotalDailyDosage );
        newSpecialDrugTracking.add( createWbcObservation( "wbcObservation", "10.0" ) );

        return newSpecialDrugTracking;
    }


    /*
     * <xsd:complexType name="Medicine"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="cmopDrugCode" type="basedatatypes:HL72CodedElementLite"/> 
     *      <xsd:element minOccurs="0" name="medicationCode" type="basedatatypes:HL72CodedElement"/>
     *      <xsd:element minOccurs="0" name="otcCode" type="basedatatypes:HL72CodedElementLite"/> 
     *      <xsd:element minOccurs="0" name="tradeName" type="basedatatypes:HL72CodedElementLite"/>
     *  </xsd:sequence> 
     *  </xsd:complexType>
     */
    private Element createMedicine( String elementName, String type )
    {
        Element newMedicine = DocumentHelper.createElement( elementName );

        newMedicine.add( createHL72CodedElementLite( "cmopDrugCode", type + " CmopDrugCd" ) );
        newMedicine.add( createHL72CodedElement( "medicationCode", " Med Alt Code" ) );
        newMedicine.add( createHL72CodedElementLite( "otcCode", type + " NDFCd" ) );
        newMedicine.add( createHL72CodedElementLite( "tradeName", type + " TradeNm" ) );

        return newMedicine;
    }


    /*
     * <xsd:complexType name="WbcObservation"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="count" type="basedatatypes:PhysicalQuantity"/>
     *      <xsd:element minOccurs="0" name="testDate" type="basedatatypes:PointInTime"/> 
     *  </xsd:sequence> 
     * </xsd:complexType>
     */
    private Element createWbcObservation( String elementName, String count )
    {
        Element newWbcObservation = DocumentHelper.createElement( elementName );
        newWbcObservation.add( createPhysicalQuantity( "count", count ) );
        newWbcObservation.add( createPointInTime( "testDate" ) );

        return newWbcObservation;
    }


    /*
     * <xsd:complexType name="ActivityLog"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="activityDate" type="basedatatypes:PointInTime"/>
     *      <xsd:element minOccurs="0" name="reason" type="basedatatypes:HL72CodedElementLite"/> 
     *      <xsd:element minOccurs="0" name="initiator" type="common:PractitionerParticipationLite"/>
     *      <xsd:element minOccurs="0" name="comment" type="xsd:string"/>
     *  </xsd:sequence> 
     * </xsd:complexType>
     */
    private Element createActivityLog( String elementName )
    {
        Element newActivityLog = DocumentHelper.createElement( elementName );

        newActivityLog.add( createPointInTime( "activityDate" ) );
        newActivityLog.add( createHL72CodedElementLite( "reason", "Reason" ) );
        newActivityLog.add( createPractitionerParticipationLite( "initiator", "Initiator Comment", INITIATOR_IDS ) );
        newActivityLog.add( createSimpleStringElement( "comment", "ActivityLog Comment" ) );

        return newActivityLog;
    }


    /*
     * <xsd:complexType name="CancelAct"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="cancelDate" type="basedatatypes:PointInTime"/>
     *      <xsd:element maxOccurs="unbounded" minOccurs="0" name="comments" type="xsd:string"/> 
     *   </xsd:sequence> 
     * </xsd:complexType>
     */
    // creates cancelact with the given date
    private Element createCancelAct( String elementName, java.util.Date date )
    {
        Element newCancelAct = DocumentHelper.createElement( elementName );

        newCancelAct.add( createPointInTime( "cancelDate", date ) );
        newCancelAct.elements().addAll( createSimpleStringElements( "comments", "CancelAct_Comment", 2 ) );

        return newCancelAct;
    }


    private Element createCancelAct( String elementName )
    {
        return createCancelAct( elementName, new Date() );
    }


    /*
     * <xsd:complexType name="MedicationInstructionComponent"> 
     *      <xsd:sequence>
     *          <xsd:element minOccurs="0" name="conjunction" type="basedatatypes:HL72CodedElementLite"/> <xsd:element minOccurs="0" name="dispenseUnitsPerDose" type="xsd:string"/> 
     *          <xsd:element minOccurs="0" name="dosageOrdered" type="xsd:string"/> 
     *          <xsd:element minOccurs="0" name="noun" type="basedatatypes:HL72CodedElementLite"/>
     *          <xsd:element minOccurs="0" name="route" type="basedatatypes:HL72CodedElementLite"/> 
     *          <xsd:element minOccurs="0" name="schedule" type="basedatatypes:HL72CodedElementLite"/> 
     *          <xsd:element minOccurs="0" name="verb" type="basedatatypes:HL72CodedElementLite"/>
     *          <xsd:element minOccurs="0" name="giveUnits" type="basedatatypes:HL72CodedElementLite"/> 
     *          <xsd:element minOccurs="0" name="intendedDuration" type="xsd:string"/> 
     *      </xsd:sequence>
     * </xsd:complexType>
     */
    private Element createMedicationInstructionComponent( String elementName )
    {
        Element newMedicationInstructionComponent = DocumentHelper.createElement( elementName );

        newMedicationInstructionComponent.add( createHL72CodedElementLite( "conjunction", "Conjunction" ) );
        newMedicationInstructionComponent.add( createSimpleStringElement( "dispenseUnitsPerDose", "15.0" ) );
        newMedicationInstructionComponent.add( createSimpleStringElement( "dosageOrdered", "DosageOrdered" ) );
        newMedicationInstructionComponent.add( createHL72CodedElementLite( "noun", "Noun" ) );
        newMedicationInstructionComponent.add( createHL72CodedElementLite( "route", "Route" ) );
        newMedicationInstructionComponent.add( createHL72CodedElementLite( "schedule", "Schedule" ) );
        newMedicationInstructionComponent.add( createHL72CodedElementLite( "verb", "Verb" ) );
        newMedicationInstructionComponent.add( createHL72CodedElementLite( "giveUnits", "VistaGiveUnits" ) );
        newMedicationInstructionComponent.add( createSimpleStringElement( "intendedDuration", "IntendedDuration" ) );

        return newMedicationInstructionComponent;
    }


    /*
     * <xsd:complexType name="TreatmentFactor"> 
     *  <xsd:sequence> 
     *      <xsd:element minOccurs="0" name="factor" type="basedatatypes:HL72CodedElementLite"/>
     *      <xsd:element minOccurs="0" name="factorValue" type="basedatatypes:HL72CodedElementLite"/> 
     *  </xsd:sequence>
     * </xsd:complexType>
     */
    private Element createTreatmentFactor( String elementName )
    {
        Element newTreatmentFactor = DocumentHelper.createElement( elementName );

        newTreatmentFactor.add( createHL72CodedElementLite( "factor", "Factor" ) );
        newTreatmentFactor.add( createHL72CodedElementLite( "factorValue", "FactorValue" ) );

        return newTreatmentFactor;
    }


    /*
     * <xsd:complexType abstract="true" name="MedicationDispense">
     *  <xsd:sequence> 
     *      <xsd:element maxOccurs="unbounded" minOccurs="0" name="comments" type="xsd:string"/> 
     *      <xsd:element minOccurs="0" name="dispenseDate" type="basedatatypes:PointInTime"/> 
     *      <xsd:element minOccurs="0" name="fillDate" type="basedatatypes:PointInTime"/>
     *      <xsd:element minOccurs="0" name="quantityDispensed" type="basedatatypes:PhysicalQuantity"/> 
     *      <xsd:element minOccurs="0" name="currentProvider" type="common:PractitionerLite"/> 
     *      <xsd:element maxOccurs="unbounded" minOccurs="0" name="currentProviderComments" type="xsd:string"/> 
     *      <xsd:element minOccurs="0" name="loginDate" type="basedatatypes:PointInTime"/> 
     * </xsd:sequence> 
     *</xsd:complexType>
     * 
     * <xsd:complexType name="OutpatientMedicationDispense">
     *   <xsd:complexContent> 
     *      <xsd:extension base="pharmacy:MedicationDispense">
     *          <xsd:sequence> 
     *              <xsd:element minOccurs="0" name="daysSupply" type="xsd:string"/> <xsd:element minOccurs="0" name="identifier" type="basedatatypes:HL72EntityIdentifier"/> 
     *              <xsd:element minOccurs="0" name="levelOfUnderstanding" type="basedatatypes:HL72CodedElementLite"/>
     *              <xsd:element minOccurs="0" name="mailWindow" type="xsd:string"/>
     *              <xsd:element minOccurs="0" name="releaseDate"type="basedatatypes:PointInTime"/> 
     *              <xsd:element minOccurs="0" name="wasPatientCounseled" type="basedatatypes:HL72CodedElementLite"/>
     *              <xsd:element minOccurs="0" name="division" type="common:PharmacyDivision"/> 
     *              <xsd:element minOccurs="0" name="dispensedDrug" type="pharmacy:DispensedDrugInstance"/> 
     *              <xsd:element minOccurs="0" name="pharmacist" type="common:PractitionerParticipationLite"/> 
     *              <xsd:element minOccurs="0" name="cmopEventStatus" type="basedatatypes:HL72CodedElementLite"/>
     *              <xsd:element minOccurs="0" name="numberOfRefillsRemaining" type="xsd:int"/> 
     *          </xsd:sequence> 
     *      </xsd:extension> 
     *  </xsd:complexContent>
     * </xsd:complexType>
     */
    public Element createOutpatientMedicationDispense( String elementName, String type, int id )
    {
        Element newOutpatientMedicationDispense = DocumentHelper.createElement( elementName );

        newOutpatientMedicationDispense.elements().addAll( createSimpleStringElements( "comments", "Comments", 2 ) );
        newOutpatientMedicationDispense.add( createPointInTime( "dispenseDate" ) );
        newOutpatientMedicationDispense.add( createPointInTime( "fillDate" ) );
        newOutpatientMedicationDispense.add( createPhysicalQuantity( "quantityDispensed" ) );
        newOutpatientMedicationDispense.add( createPractitionerLite( "currentProvider", CURRENTPROVIDER_IDS ) );
        newOutpatientMedicationDispense.elements().addAll( createSimpleStringElements( "currentProviderComments", "ProviderComments", 2 ) );
        newOutpatientMedicationDispense.add( createPointInTime( "loginDate" ) );
        newOutpatientMedicationDispense.add( createSimpleStringElement( "daysSupply", "5" ) );
        newOutpatientMedicationDispense.add( createHL72EntityIdentifier( "identifier", id ) );
        newOutpatientMedicationDispense.add( createHL72CodedElementLite( "levelOfUnderstanding", "LevelOfUnderstanding" ) );
        newOutpatientMedicationDispense.add( createSimpleStringElement( "mailWindow", "MailWindow" ) );
        newOutpatientMedicationDispense.add( createPointInTime( "releaseDate" ) );
        newOutpatientMedicationDispense.add( createHL72CodedElementLite( "wasPatientCounseled", "WasPatientCounseled" ) );
        newOutpatientMedicationDispense.add( createPharmacyDivision( "division", "DivisionId", "NcpdpId" ) );
        newOutpatientMedicationDispense.add( createDispensedDrugInstance( "dispensedDrug", type ) );
        newOutpatientMedicationDispense.add( createPractitionerParticipationLite( "pharmacist", "Pharmacist Comment", PHARMACIST_IDS ) );
        newOutpatientMedicationDispense.add( createHL72CodedElementLite( "cmopEventStatus", "CmopEventStatus" ) );
        newOutpatientMedicationDispense.add( createSimpleIntegerElement( "numberOfRefillsRemaining", 13 ) );

        return newOutpatientMedicationDispense;
    }


    /*
     * <xsd:complexType name="DispensedDrugInstance"> 
     *  <xsd:sequence>
     *      <xsd:element minOccurs="0" name="drugUnitPrice" type="basedatatypes:Money"/> 
     *      <xsd:element minOccurs="0" name="expirationDate" type="basedatatypes:PointInTime"/> 
     *      <xsd:element minOccurs="0" name="lotId" type="xsd:string"/> 
     *      <xsd:element minOccurs="0" name="ndc" type="basedatatypes:HL72CodedElementLite"/> 
     *  </xsd:sequence>
     * </xsd:complexType>
     */
    private Element createDispensedDrugInstance( String elementName, String type )
    {
        Element newDispensedDrugInstance = DocumentHelper.createElement( elementName );

        newDispensedDrugInstance.add( createMoney( "drugUnitPrice" ) );
        newDispensedDrugInstance.add( createPointInTime( "expirationDate" ) );
        newDispensedDrugInstance.add( createSimpleStringElement( "lotId", type + "newLotId" ) );
        newDispensedDrugInstance.add( createHL72CodedElementLite( "ndc", type + "Ndc" ) );

        return newDispensedDrugInstance;
    }

}
