

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


import java.util.ArrayList;
import java.util.List;
import java.util.Random;

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


public class LabBuilder
    extends
        AbstractEntryPointBuilder
{
    public static final String[] DOCTOR_IDS = { "test_DOCTORID_1001", "test_DOCTORID_1002", "test_DOCTORID_1003", "test_DOCTORID_1004" };
    public static final String[] VERIFIER_IDS = { "test_verifierid_11001", "test_verifierid_11002", "test_verifierid_11003" };
    protected static Log logger = null;
    private static final int RECORD_VERSION = 12345;

    private int LAB_IDX = 50000;

    public LabBuilder( )
    {
        super();
    }


    public LabBuilder( Random random )
    {
        super( random );
    }


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


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


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


    public Element makeLabTestPromise( Element patient )
    {
        Element lab = createLabTestPromise( LAB_IDX++ , patient );

        return lab;
    }


    public List<Element> makeLabTestPromise( int number, Element patient )
    {
        List<Element> labs = new ArrayList<Element>( number );
        for ( int i = 0; i < number; i++ )
        {
            labs.add( makeLabTestPromise( patient ) );
        }
        return labs;

    }


    /*
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!--  LabTestPromise  <<vHIMClass, act>>  -->
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
  <xsd:complexType name="LabTestPromise">
    <xsd:sequence>
      <xsd:element name="recordIdentifier" type="basedatatypes:HL72EntityIdentifier"/>
      <xsd:element name="patient" type="common:PatientLite"/>
      <xsd:element minOccurs="0" name="placerOrderIdentifier" type="basedatatypes:HL72EntityIdentifier"/>
      <xsd:element minOccurs="0" name="placerAccessionReference" type="xsd:string"/>
      <xsd:element minOccurs="0" name="fillerIenReference" type="xsd:string"/>
      <xsd:element minOccurs="0" name="reportCompleteDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="labSubscript" type="xsd:string"/>
      <xsd:element minOccurs="0" name="priority" type="xsd:string"/>
      <xsd:element minOccurs="0" name="status" type="xsd:string"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="labCommentEvents" type="lab:LabCommentEvent"/>
      <xsd:element minOccurs="0" name="labTestRequest" type="lab:LabTestRequest"/>
      <xsd:element minOccurs="0" name="patientVisit" type="lab:LabPatientVisit"/>
      <xsd:element name="specimen" type="lab:Specimen"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="labTests" type="lab:LabTest"/>
      <xsd:element minOccurs="0" name="recordSource" type="basedatatypes:HL72FacilityIdentifier"/>
      <xsd:element name="recordVersion" type="xsd:int"/>
      <xsd:element name="recordUpdateTime" type="basedatatypes:PointInTime"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    public Element createLabTestPromise(int id, Element labPatient )
    {
        Element newLabTestPromise = DocumentHelper.createElement("labTestPromises" );
        
        Element newRecordIdentifier = createHL72EntityIdentifier("recordIdentifier", id );
        newLabTestPromise.add( newRecordIdentifier );

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

        Element newPlacerOrderIdentifier = createHL72EntityIdentifier("placerOrderIdentifier");
        newLabTestPromise.add( newPlacerOrderIdentifier );

        newLabTestPromise.addElement( "placerAccessionReference" ).addText( "PlacerAccessionReference" );

        newLabTestPromise.addElement( "fillerIenReference" ).addText( "FillerIenReference" );

        Element newReportCompleteDate = createPointInTime("reportCompleteDate");
        
        newLabTestPromise.add( newReportCompleteDate );

        newLabTestPromise.addElement( "labSubscript" ).addText( "CH" );
        
        newLabTestPromise.addElement( "priority" ).addText( "Priority" );

        newLabTestPromise.addElement( "status" ).addText( "Status" );

        Element newLabCommentEvent = makeLabCommentEvent( "LabTestPromise.LabCommentEvent1", "One" );
        newLabTestPromise.add( newLabCommentEvent );
        newLabCommentEvent = makeLabCommentEvent( "LabTestPromise.LabCommentEvent2", "Two" );
        newLabTestPromise.add( newLabCommentEvent );

        Element newLabTestRequest = makeLabTestRequest();
        newLabTestPromise.add( newLabTestRequest );

     //   Element newHL72PersonName = createHL72PersonName();
        Element newLabPatientVisit = makeLabPatientVisit();
        newLabTestPromise.add( newLabPatientVisit );

        Element newSpecimen = makeSpecimen( "Specimen" );
        newLabTestPromise.add( newSpecimen );

        Element newLabTest = makeLabTest( "LabTest1", "OTCode1" );
        newLabTestPromise.add( newLabTest );
        newLabTest = makeLabTest( "LabTest2", "OTCode2" );
        newLabTestPromise.add( newLabTest );

        Element newRecordSource = createHL72FacilityIdentifier("recordSource");
        newLabTestPromise.add( newRecordSource );

        newLabTestPromise.addElement( "recordVersion" ).addText( new Integer(RECORD_VERSION).toString() );
        
        Element newRecordUpdateTime = createPointInTime("recordUpdateTime");
        newLabTestPromise.add( newRecordUpdateTime );

        return newLabTestPromise;
    }


    /*
  <xsd:complexType name="LabCommentEvent">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="commentTypeCode" type="basedatatypes:HL72CodedElementLite"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="comments" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    public Element makeLabCommentEvent( String commentText, String codePrefix )
    {
        Element newLabCommentEvent = DocumentHelper.createElement("labCommentEvents" );
        
        Element newCommentTypeCode = BaseDatatypesBuilder.createHL72CodedElementLite( "commentTypeCode", codePrefix );
        newLabCommentEvent.add( newCommentTypeCode );

        newLabCommentEvent.addElement( "comments" ).addText( commentText + ".   Comment1"  );
        newLabCommentEvent.addElement( "comments" ).addText( commentText + "    .Comment2"  );

        return newLabCommentEvent;
    }


    /*
  <xsd:complexType name="LabTest">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="procedureCode" type="basedatatypes:HL72CodedElement"/>
      <xsd:element minOccurs="0" name="orderedTestCode" type="basedatatypes:HL72CodedElement"/>
      <xsd:element minOccurs="0" name="fillerAccessionReference" type="xsd:string"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="chemistryResults" type="lab:ChemistryResult"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element makeLabTest( String labPrefix, String orderedTestCodePrefix )
    {
        Element newLabTest = DocumentHelper.createElement("labTests" );

        Element newProdedureCode = createHL72CodedElement( "procedureCode" , "ProcedureCode" );
        newLabTest.add( newProdedureCode );

        Element newOrderedTestCode = createHL72CodedElement( "orderedTestCode" , orderedTestCodePrefix );
        newLabTest.add( newOrderedTestCode );

        newLabTest.addElement( "fillerAccessionReference" ).addText( "FillerAccessionReference" );

        Element newChemistryResult = makeChemistryResult( labPrefix + ".ChemistryResult1" );
        newLabTest.add( newChemistryResult );
        newChemistryResult = makeChemistryResult( labPrefix + ".ChemistryResult2" );
        newLabTest.add( newChemistryResult );

        return newLabTest;
    }


    private Element makeUsMailingAddress(String elementName )
    {
        return BaseDatatypesBuilder.createUsMailingAddress(elementName);
    }


    /*
  <xsd:complexType name="LabPatientVisit">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="patientClass" type="xsd:string"/>
      <xsd:element minOccurs="0" name="assignedLocation" type="basedatatypes:HL72LocationIdentifier"/>
      <xsd:element minOccurs="0" name="priorLocation" type="basedatatypes:HL72LocationIdentifier"/>
      <xsd:element minOccurs="0" name="attendingDoctor" type="common:PractitionerLite"/>
      <xsd:element minOccurs="0" name="hospitalService" type="xsd:string"/>
      <xsd:element minOccurs="0" name="patientType" type="xsd:string"/>
      <xsd:element minOccurs="0" name="chargePriceIndicator" type="xsd:string"/>
      <xsd:element minOccurs="0" name="dischargeDisposition" type="xsd:string"/>
      <xsd:element minOccurs="0" name="servicingFacility" type="xsd:string"/>
      <xsd:element minOccurs="0" name="admissionDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="alternateVisitId" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    public Element makeLabPatientVisit( )
    {
        Element newLabPatientVisit = DocumentHelper.createElement("patientVisit" );
        
        newLabPatientVisit.addElement( "patientClass" ).addText( "PatientClass" );

        Element newAssignedLocation = createHL72LocationIdentifier( "assignedLocation", "AssignedLocation" );
        newLabPatientVisit.add( newAssignedLocation );

        Element newPriorLocation = createHL72LocationIdentifier( "priorLocation" , "PriorLocation" );
        newLabPatientVisit.add( newPriorLocation );

        Element attendingDoctor = createPractitionerLite( "attendingDoctor" , DOCTOR_IDS );
        newLabPatientVisit.add( attendingDoctor );

        newLabPatientVisit.addElement( "hospitalService" ).addText( "HospitalService" );

        newLabPatientVisit.addElement( "patientType" ).addText( "PatientType" );
        
        newLabPatientVisit.addElement( "chargePriceIndicator" ).addText( "ChargePriceIndicator" );

        newLabPatientVisit.addElement( "dischargeDisposition" ).addText( "DischargeDisposition" );

        newLabPatientVisit.addElement( "servicingFacility" ).addText( "ServicingFacility" );

        Element newAdmissionDate = createFixedPointInTime("admissionDate");
        newLabPatientVisit.add( newAdmissionDate );

        newLabPatientVisit.addElement( "alternateVisitId" ).addText( "AlternateVisitId" );

        return newLabPatientVisit;
    }


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


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


    protected void printLabTestPromise( Element labTestPromise )
    {
        printDomainRecord( labTestPromise );
    }


    protected void printLabTestPromise( Element labTestPromise, Logger logger )
    {
        printDomainRecord( labTestPromise, logger );
    }


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

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

        return returnString;
    }


    /*
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!--  ChemistryResult  <<vHIMClass, observation>>  -->
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
  <xsd:complexType name="ChemistryResult">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="valueInterpretation" type="xsd:string"/>
      <xsd:element minOccurs="0" name="observationDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="observationStatus" type="xsd:string"/>
      <xsd:element minOccurs="0" name="testIdentifier" type="basedatatypes:HL72CodedElementExtended"/>
      <xsd:element minOccurs="0" name="referenceRange" type="xsd:string"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="labCommentEvents" type="lab:LabCommentEvent"/>
      <xsd:element minOccurs="0" name="observationValue" type="xsd:string"/>
      <xsd:element minOccurs="0" name="observationUnits" type="basedatatypes:HL72CodedElementLite"/>
      <xsd:element minOccurs="0" name="deviceIdentifier" type="basedatatypes:HL72EntityIdentifier"/>
      <xsd:element minOccurs="0" name="observationValueType" type="xsd:string"/>
      <xsd:element minOccurs="0" name="producerCode" type="basedatatypes:HL72CodedElement"/>
      <xsd:element minOccurs="0" name="verifier" type="common:PractitionerLite"/>
      <xsd:element minOccurs="0" name="analysisDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="performingOrganization" type="lab:PerformingOrganization"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="observationMethods" type="lab:ObservationMethod"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element makeChemistryResult( String type )
    {
        Element newChemistryResult = DocumentHelper.createElement("chemistryResults" );
        
        newChemistryResult.addElement( "valueInterpretation" ).addText( "Interpretation" + type );

        Element newObservationDate = createFixedPointInTime("observationDate");
        newChemistryResult.add( newObservationDate );

        newChemistryResult.addElement( "observationStatus" ).addText(  "Status" + type );

        Element newTestIdentifier = createHL72CodedElementExtended( "testIdentifier", "TestCode" + type );
        newChemistryResult.add( newTestIdentifier );

        newChemistryResult.addElement( "referenceRange" ).addText(  "VistaReferenceRange" + type );

        Element newComment1 = makeLabCommentEvent( type + ".LabCommentEvent1", "One" );
        newChemistryResult.add( newComment1 );
        //newChemistryResult.getLabCommentEvents().add( newComment1 );

        Element newComment2 = makeLabCommentEvent( type + ".LabCommentEvent2", "Two" );
        newChemistryResult.add( newComment2 );

        newChemistryResult.addElement( "observationValue" ).addText( "ObservationValue" );
        
        Element newObservationUnits = createHL72CodedElementLite( "observationUnits" , "ObservationUnits" + type );
        newChemistryResult.add( newObservationUnits );

        Element newDeviceIdentifier = createHL72EntityIdentifier("deviceIdentifier");
        newChemistryResult.add( newDeviceIdentifier );

        newChemistryResult.addElement( "observationValueType" ).addText( "ObservationValueType" + type );
        

        Element newProducerCode = createHL72CodedElement( "producerCode" , "ProducerCode" + type );
        newChemistryResult.add( newProducerCode );

        Element newVerifier = this.createPractitionerLite( "verifier" , VERIFIER_IDS );
        newChemistryResult.add( newVerifier );

        Element newAnalysisDate = createFixedPointInTime("analysisDate");
        newChemistryResult.add( newAnalysisDate );

        Element newPerformingOrganization = makePerformingOrganization();
        newChemistryResult.add( newPerformingOrganization );

        Element newObservationMethod1 = createObservationMethod( type + "1" );
        newChemistryResult.add( newObservationMethod1 );

        Element newObservationMethod2 = createObservationMethod( type + "2" );
        newChemistryResult.add( newObservationMethod2 );

        return newChemistryResult;
    }


    /*
  <xsd:complexType name="ObservationMethod">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="observationMethodCode" type="basedatatypes:HL72CodedElement"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element createObservationMethod( String string )
    {
        Element newObservationMethod = DocumentHelper.createElement("observationMethods" );
        
        Element newObservationMethodCode = createHL72CodedElement( "observationMethodCode", "AMethodCode" + string );
        newObservationMethod.add( newObservationMethodCode );

        return newObservationMethod;
    }


    /*
  <xsd:complexType name="LabTestRequest">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="author" type="common:PractitionerLite"/>
      <xsd:element minOccurs="0" name="requestingLocationIdentifier" type="basedatatypes:HL72LocationIdentifier"/>
      <xsd:element minOccurs="0" name="requestingOrganization" type="basedatatypes:HL72CodedElementLite"/>
      <xsd:element minOccurs="0" name="orderingFacilityIdentifier" type="basedatatypes:HL72OrganizationIdentifierExtended"/>
      <xsd:element minOccurs="0" name="orderingFacilityAddress" type="basedatatypes:UsMailingAddress"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element makeLabTestRequest( )
    {
        Element newLabTestRequest = DocumentHelper.createElement("labTestRequest" );
        
        Element newAuthor = createPractitionerLite("author", AUTHOR_IDS );
        newLabTestRequest.add( newAuthor );

        Element newRequestingLocationIdentifier = createHL72LocationIdentifier("requestingLocationIdentifier");
        newLabTestRequest.add( newRequestingLocationIdentifier );

        Element newRequestingOrganization = createHL72CodedElementLite( "requestingOrganization", "ROCode" );
        newLabTestRequest.add( newRequestingOrganization );

        Element newOrderingFacilityIdentifier = createHL72OrganizationIdentifierExtended("orderingFacilityIdentifier");
        newLabTestRequest.add( newOrderingFacilityIdentifier );

        Element newOrderingFacilityAddress = makeUsMailingAddress("orderingFacilityAddress");
        newLabTestRequest.add( newOrderingFacilityAddress );

        return newLabTestRequest;
    }


    /*
  <xsd:complexType name="PerformingOrganization">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="identifier" type="basedatatypes:HL72OrganizationIdentifierExtended"/>
      <xsd:element minOccurs="0" name="address" type="basedatatypes:UsMailingAddress"/>
      <xsd:element minOccurs="0" name="medicalDirector" type="basedatatypes:HL72PersonName"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element makePerformingOrganization( )
    {
        Element newPerformingOrganization = DocumentHelper.createElement("performingOrganization" );
        
        Element newIdentifier = createHL72OrganizationIdentifierExtended("identifier");
        newPerformingOrganization.add( newIdentifier );

        Element newAddress = makeUsMailingAddress("address");
        newPerformingOrganization.add( newAddress );

        Element newMedicalDirector = createHL72PersonName("medicalDirector");
        newPerformingOrganization.add( newMedicalDirector );

        return newPerformingOrganization;
    }


    /*
  <xsd:complexType name="Specimen">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="specimenSource" type="basedatatypes:HL72CodedElementExtended"/>
      <xsd:element minOccurs="0" name="specimenTakenDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="specimenReceivedDate" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="specimenAction" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
     */
    private Element makeSpecimen( String type )
    {
        Element newSpecimen = DocumentHelper.createElement("specimen" );

        Element newSpecimenSource = createHL72CodedElementExtended( "specimenSource","SSCode" + type );
        newSpecimen.add( newSpecimenSource );

        Element newSpecimenTakenDate = createPointInTime("specimenTakenDate");
        newSpecimen.add( newSpecimenTakenDate );

        Element newSpecimenReceivedDate = createPointInTime("specimenReceivedDate");
        newSpecimen.add( newSpecimenReceivedDate );

        newSpecimen.addElement( "specimenAction").addText( "SpecimenAction" );

        return newSpecimen;
    }

}
