

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


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

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


public class IntoleranceConditionBuilder
    extends
        AbstractEntryPointBuilder
{
    private static int INTOLERANCE_CONDITION_IDX = 10000;
    private static final int INTOLERANCE_CONDITION_IDX_DEFAULT = 10000;

    public static final String FOOD_TYPE = "Food";
    public static final String DRUG_TYPE = "Drug";
    public static final String FOOD_DRUG_TYPE = "Food/Drug";
    public static final String OTHER_TYPE = "Other";
    public static final String[] ALLERGY_TYPES = { FOOD_TYPE, DRUG_TYPE, FOOD_DRUG_TYPE, OTHER_TYPE };
    public static final String[] FOOD_ALLERGEN = { "Peanuts", "Protein", "MSG", "Starch" };
    public static final String[] DRUG_ALLERGEN = { "Sulfa", "Aspirin", "Codeine", "Penicillin" };
    public static final String[] FOOD_DRUG_ALLERGEN = { "FoodDrug1", "FoodDrug2", "FoodDrug3", "FoodDrug4" };
    public static final String[] OTHER_ALLERGEN = { "Other1", "Other2", "Other3", "Other4" };
    public static final String[] DRUG_CLASSES = { "Class1", "Class2", "Class3", "Class4", "Class5", "Class6" };
    public static final String[] DRUG_INGREDIENTS = { "Ingredient1", "Ingredient2", "Ingredient3", "Ingredient4", "Ingredient5", "Ingredient6" };
    public static final String[] REACTION = { "Hives", "Cough", "Seizure" };
    public static final String[] DATA_ENTERER_IDS = { "test_ENTERERID_1", "test_ENTERERID_2", "test_ENTERERID_3" };
    public static final String[] VERIFIER_IDS = { "test_VERIFIERID_2001", "test_VERIFIERID_2002", "test_VERIFIERID_2003", "test_VERIFIERID_2004",
                    "test_IDS_2005" };
    public static final String[] IDBANDUPDATER_IDS = { "test_IDBANDUPDATERID_3001", "test_IDBANDUPDATERID_3002", "test_IDBANDUPDATERID_3003",
                    "test_IDBANDUPDATERID_3004", "test_IDBANDUPDATERID_3005" };
    public static final String[] CHARTMARKER_IDS = { "test_CHARTMARKERID_4001", "test_CHARTMARKERID_4002", "test_CHARTMARKERID_4003",
                    "test_CHARTMARKERID_4004", "test_CHARTMARKERID_4005" };
    public static final String[] ERRORENTERER_IDS = { "test_ERRORENTERERID_5001", "test_ERRORENTERERID_5002", "test_ERRORENTERERID_5003",
                    "test_ERRORENTERERID_5004", "test_ERRORENTERERID_5005" };
    // private Random random;
    private HashMap<String, String[]> agents = new HashMap<String, String[]>();
   
    public IntoleranceConditionBuilder( )
    {
        this( new Random() );
    }


    public IntoleranceConditionBuilder( Random aRandom )
    {
        super( aRandom );
        agents.put( FOOD_TYPE, FOOD_ALLERGEN );
        agents.put( DRUG_TYPE, DRUG_ALLERGEN );
        agents.put( FOOD_DRUG_TYPE, FOOD_DRUG_ALLERGEN );
        agents.put( OTHER_TYPE, OTHER_ALLERGEN );
    }


    public void resetIndex( )
    {
        INTOLERANCE_CONDITION_IDX = INTOLERANCE_CONDITION_IDX_DEFAULT;
    }


    public Element makeInsertAllergy( )
    {
        Element intoleranceCondition = makeAllergy();

        return intoleranceCondition;
    }


    public List<Element> makeInsertAllergies( int count )
    {
        List<Element> intoleranceConditions = makeAllergies( count );

        return intoleranceConditions;
    }


    public Element makeAllergy( )
    {
        Element allergyType = createHL72CodedElementLite( "allergyType", "AllergyType", ALLERGY_TYPES );
        return makeAllergy( allergyType, null, false );
    }


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


    public Element makeAllergyWithPatient( Element patient )
    {
        Element allergyType = createHL72CodedElementLite( "allergyType", "AllergyType", ALLERGY_TYPES );
        return makeAllergy( allergyType, patient, false );
    }


    public Element makeAllergyWithCommentEvent( String comment )
    {
        Element newAllergyCommentEvent = makeAllergyCommentEvent( "comment", comment, "commentEvent" );

        return newAllergyCommentEvent;
    }


    public Element makeAllergyWithAllergyType( Element allergyType )
    {
        return makeAllergy( allergyType, null, false );
    }


    public Element makeAllergy( Element allergyType, Element patient )
    {
        return makeAllergy( allergyType, patient, false );
    }


    public Element makeAllergy( Element allergyType, Element patient, boolean repeatable )
    {
        Element allergy = createIntoleranceCondition( INTOLERANCE_CONDITION_IDX++ , allergyType, patient, repeatable );

        return allergy;
    }


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


    public List<Element> makeAllergies( int number, Element patient )
    {
        Element allergyType = null;
        List<Element> allergies = new ArrayList<Element>( number );
        for ( int i = 0; i < number; i++ )
        {
            allergyType = createHL72CodedElementLite( "allergyType", "AllergyType", ALLERGY_TYPES );
            allergies.add( makeAllergy( allergyType, patient, false ) );
        }

        return allergies;
    }


    public List<Element> makeAllergies( Element allergyType, int aNumber )
    {
        return makeAllergies( allergyType, aNumber, random, null );
    }


    public List<Element> makeAllergies( Element allergyType, int number, Element patient )
    {
        return makeAllergies( allergyType, number, random, patient );
    }


    public List<Element> makeAllergies( Element allergyType, int number, Random random, Element patient )
    {
        List<Element> allergies = new ArrayList<Element>( number );
        for ( int i = 0; i < number; i++ )
        {
            allergies.add( makeAllergy( allergyType, patient, false ) );
        }

        return allergies;
    }


    public List<Element> makeAllergies( Element allergyType, int number, Random random, Element patient, boolean resetIndex )
    {
        if ( resetIndex )
        {
            resetIndex();
        }
        List<Element> allergies = new ArrayList<Element>( number );
        for ( int i = 0; i < number; i++ )
        {
            allergies.add( makeAllergy( allergyType, patient, true ) );
        }

        return allergies;
    }


    /*
    <xsd:complexType name="IntoleranceCondition">
        <xsd:sequence>
            <xsd:element name="recordIdentifier" type="basedatatypes:HL72EntityIdentifier"/>
            <xsd:element name="patient" type="common:PatientLite"/>
            <xsd:element name="observationTime" type="basedatatypes:PointInTime" minOccurs="0"/>
            <xsd:element name="agent" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
            <xsd:element name="allergyType" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
            <xsd:element name="gmrAllergyAgent" type="basedatatypes:HL72CodedElement" minOccurs="0"/>
            <xsd:element name="informationSourceCategory" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
            <xsd:element name="mechanism" type="basedatatypes:HL72CodedElementLite" minOccurs="0"/>
            <xsd:element name="status" type="xsd:string" minOccurs="0"/>
            <xsd:element name="verified" type="xsd:string" minOccurs="0"/>
            <xsd:element name="reaction" type="allergies:ReactionObservationEvent" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="verifier" type="common:PractitionerParticipationLite" minOccurs="0"/>
            <xsd:element name="author" type="common:PractitionerParticipationLite" minOccurs="0"/>
            <xsd:element name="errorEnterer" type="common:PractitionerParticipationLite" minOccurs="0"/>
            <xsd:element name="idBandMarker" type="common:PractitionerParticipationLite" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="chartMarker" type="common:PractitionerParticipationLite" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="commentEvents" type="allergies:AllergyCommentEvent" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="drugClass" type="allergies:DrugClass" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="drugIngredient" type="allergies:DrugIngredient" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="facilityIdentifier" type="basedatatypes:HL72OrganizationIdentifier" minOccurs="0"/>
            <xsd:element name="recordSource" type="basedatatypes:HL72FacilityIdentifier" minOccurs="0"/>
            <xsd:element name="recordVersion" type="xsd:int"/>
            <xsd:element name="recordUpdateTime" type="basedatatypes:PointInTime"/>
        </xsd:sequence>
    </xsd:complexType>
     */
    private Element createIntoleranceCondition( int id, Element agentElement, Element patient, boolean repeatable )
    {
        Element element = DocumentHelper.createElement( "intoleranceConditions" );

        element.add( createHL72EntityIdentifier( "recordIdentifier", id ) );
        Element newPatient = createPatientLite( "patient" );
        if ( patient != null )
        {
            newPatient.element( "identifier" ).element( "identity" ).setText( patient.elementText( "identity" ) );
            newPatient.element( "identifier" ).element( "assigningFacility" ).setText( patient.elementText( "assigningFacility" ) );
            newPatient.element( "identifier" ).element( "assigningAuthority" ).setText( patient.elementText( "assigningAuthority" ) );            
        }
        element.add( newPatient );
        element.add( createPointInTime( "observationTime" ) );

        String allergyAgentValue = getRandomValueFromArray( ( String[] )agents.get( agentElement.element( "code" ).getTextTrim() ) );
        element.add( createHL72CodedElementLite( "agent", allergyAgentValue ) );
        element.add( createHL72CodedElementLite( "allergyType", agentElement ) );
        element.add( createHL72CodedElement( "gmrAllergyAgent", "Agent", allergyAgentValue ) );

        element.add( createHL72CodedElementLite( "informationSourceCategory", "ISC " ) );
        element.add( createHL72CodedElementLite( "mechanism", "Mechanism " ) );
        element.addElement( "status" ).addText( "Status" );
        element.addElement( "verified" ).addText( "True" );
        element.add( createReactionObservationEvent( "reaction" ) );
        element.add( createReactionObservationEvent( "reaction" ) );
        element.add( createPractitionerParticipationLite( "verifier", "Verifier Comment", VERIFIER_IDS ) );
        element.add( createPractitionerParticipationLite( "author", "Author Comment", AUTHOR_IDS ) );
        element.add( createPractitionerParticipationLite( "errorEnterer", "ErrorEnterer Comment", ERRORENTERER_IDS ) );
        element.add( createPractitionerParticipationLite( "idBandMarker", "ID Band Marker 1 Comment", IDBANDUPDATER_IDS ) );
        element.add( createPractitionerParticipationLite( "idBandMarker", "ID Band Marker 2 Comment", IDBANDUPDATER_IDS ) );
        element.add( createPractitionerParticipationLite( "chartMarker", "Chart Marker 1 Comment", CHARTMARKER_IDS ) );
        element.add( createPractitionerParticipationLite( "chartMarker", "Chart Marker 2 Comment", CHARTMARKER_IDS ) );
        element.add( makeAllergyCommentEvent( "commentEvents", "A comment event text 1", "commentEvent" ) );
        element.add( makeAllergyCommentEvent( "commentEvents", "A comment event text 2", "commentEvent" ) );
        element.add( makeDrugClass( "drugClass", "Drug Class 1", DRUG_CLASSES ) );
        element.add( makeDrugClass( "drugClass", "Drug Class 2", DRUG_CLASSES ) );
        element.add( makeDrugIngredient( "drugIngredient", "Drug Ing. 1", DRUG_INGREDIENTS ) );
        element.add( makeDrugIngredient( "drugIngredient", "Drug Ing. 1", DRUG_INGREDIENTS ) );
        element.add( createHL72OrganizationIdentifier( "facilityIdentifier" ) );
        element.add( createHL72FacilityIdentifier( "recordSource" ) );
        element.addElement( "recordVersion" ).addText( String.valueOf( id ) );
        element.add( createPointInTime( "recordUpdateTime" ) );

        return element;
    }


    public void printIntoleranceConditions( List<Element> aListOfIntoleranceConditions )
    {
        printDomainRecords( aListOfIntoleranceConditions );
    }


    public void printIntoleranceConditions( List<Element> aListOfIntoleranceConditions, Logger aLogger )
    {
        printDomainRecords( aListOfIntoleranceConditions, aLogger );
    }


    public void printIntoleranceCondition( Element aIntoleranceCondition )
    {
        printDomainRecord( aIntoleranceCondition );
    }


    public void printIntoleranceCondition( Element aIntoleranceCondition, Logger aLogger )
    {
        printDomainRecord( aIntoleranceCondition, aLogger );
    }


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

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


    /*
    <xsd:complexType name="AllergyCommentEvent">
    <xsd:sequence>
      <xsd:element minOccurs="0" name="date" type="basedatatypes:PointInTime"/>
      <xsd:element minOccurs="0" name="author" type="common:PractitionerLite"/>
      <xsd:element minOccurs="0" name="commentType" type="basedatatypes:HL72CodedElementLite"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="comments" type="xsd:string"/>
    </xsd:sequence>
    </xsd:complexType>
     */
    private Element makeAllergyCommentEvent( String elementName, String commentText, String codePrefix )
    {
        Element element = DocumentHelper.createElement( elementName );

        element.add( createPointInTime( "date" ) );
        element.add( createPractitionerLite( "author", AUTHOR_IDS ) );
        element.add( createHL72CodedElementLite( "commentType", codePrefix, "aCommentType" ) );
        element.addElement( "comments" ).addText( "theFirstComment" );
        element.addElement( "comments" ).addText( "theSecondComment" );

        return element;
    }


    /*
     <xsd:complexType name="DrugClass">
     <xsd:sequence>
     <xsd:element minOccurs="0" name="code" type="basedatatypes:HL72CodedElement"/>
     </xsd:sequence>
     </xsd:complexType>
     */
    private Element makeDrugClass( String elementName, String codePrefix, String[] codeValues )
    {
        Element element = DocumentHelper.createElement( elementName );

        element.add( createHL72CodedElement( "code", codePrefix, codeValues ) );

        return element;
    }


    /*
     <xsd:complexType name="DrugIngredient">
     <xsd:sequence>
     <xsd:element minOccurs="0" name="code" type="basedatatypes:HL72CodedElementLite"/>
     </xsd:sequence>
     </xsd:complexType>
     */
    private Element makeDrugIngredient( String elementName, String codePrefix, String[] codeValues )
    {
        Element element = DocumentHelper.createElement( elementName );

        element.add( createHL72CodedElementLite( "code", codePrefix, codeValues ) );

        return element;
    }


    /*
     <xsd:complexType name="ReactionObservationEvent">
     <xsd:sequence>
     <xsd:element minOccurs="0" name="observationTime" type="basedatatypes:PointInTime"/>
     <xsd:element minOccurs="0" name="reaction" type="basedatatypes:HL72CodedElementLite"/>
     <xsd:element minOccurs="0" name="author" type="common:PractitionerParticipationLite"/>
     </xsd:sequence>
     </xsd:complexType>
     */
    public Element createReactionObservationEvent( String elementName )
    {
        Element element = DocumentHelper.createElement( elementName );

        element.add( createFixedPointInTime( "observationTime" ) );
        element.add( createHL72CodedElementLite( "reaction", "Reaction " ) );
        element.add( createPractitionerParticipationLite( "author", "Comment" ) );

        return element;
    }

    public Element makeIntoleranceCondition( String elementName, String recordIdentifier )
    {

        Element intoleranceConditions = DocumentHelper.createElement( elementName );
        Element newRecordIdentifier = createHL72EntityIdentifier( "recordIdentifier", recordIdentifier );
        intoleranceConditions.add( newRecordIdentifier );
    
        return intoleranceConditions;

    }
    
    public Element makeIntoleranceCondition( String elementName, String recordIdentifier, String recordVersion )
    {

        Element intoleranceConditions = DocumentHelper.createElement( elementName );
        Element newRecordIdentifier = createHL72EntityIdentifier( "recordIdentifier", recordIdentifier );
        intoleranceConditions.add( newRecordIdentifier );
        
        Element newRecordVersion = DocumentHelper.createElement( "recordVersion" );
        newRecordVersion.addText( recordVersion );
        intoleranceConditions.add( newRecordVersion );
    
        return intoleranceConditions;

    }
}
