

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


import gov.va.med.cds.util.StreamUtil;

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

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.logging.log4j.Logger;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.core.io.ClassPathResource;


public abstract class AbstractEntryPointBuilder
    implements
        EntryPointBuilderInterface
{
    protected static final String[] AUTHOR_IDS = { "test_AUTHORID_1001", "test_AUTHORID_1002", "test_AUTHORID_1003", "test_AUTHORID_1004" };
    protected static final String APPLICATION_NAME = "CDS";
    protected static final String PATIENT_IDENTITY = "test_sourceid_1000000";
    protected static final String ASSIGNINGAUTHORITY_HDR = "USDOD";
    protected static final String ASSIGNING_FACILITY_HDR = "200DOD";

    protected Random random;


    public AbstractEntryPointBuilder( )
    {
        this( new Random() );
    }


    public AbstractEntryPointBuilder( Random aRandom )
    {
        super();
        setRandom( aRandom );
    }


    public void setRandom( Random aRandom )
    {
        this.random = aRandom;
        CommonBuilder.setRandom( aRandom );
        BaseDatatypesBuilder.setRandom( aRandom );
    }


    @SuppressWarnings( "rawtypes" )
    public void printDomainRecords( List aListOfResults )
    {
        System.out.println( "Records found: " + aListOfResults.size() );
        for ( Object object : aListOfResults )
        {
            printDomainRecord( object );
        }
    }


    @SuppressWarnings( "rawtypes" )
    public void printDomainRecords( List aListOfResults, Logger aLogger )
    {
        aLogger.debug( gov.va.med.cds.util.LogMessageUtil.buildMessage( null, null, APPLICATION_NAME, "Records found: " + aListOfResults.size() ) );
        for ( Object object : aListOfResults )
        {
            printDomainRecord( object, aLogger );
        }
    }


    public void printDomainRecord( Object aObject )
    {
        System.out.println( fillPrintBuffer( aObject ) );
    }


    public void printDomainRecord( Object aObject, Logger aLogger )
    {
        aLogger.debug( gov.va.med.cds.util.LogMessageUtil.buildMessage( null, null, APPLICATION_NAME, fillPrintBuffer( aObject ) ) );
    }


    public abstract String fillPrintBuffer( Object aObject );


    protected Element createSimpleStringElement( String elementName, String elementValue )
    {
        Element element = DocumentHelper.createElement( elementName );
        element.setText( elementValue );
        return element;
    }


    protected Element createSimpleIntegerElement( String elementName, int elementValue )
    {
        Element element = DocumentHelper.createElement( elementName );
        element.setText( Integer.toString( elementValue ) );
        return element;
    }


    protected Element createHL72PersonName( String elementName )
    {
        return BaseDatatypesBuilder.createHL7PersonName( elementName, "FamilyName", "MiddleName", "Prefix", "Given", "Suffix", "Title" );
    }


    protected Element createHL72CodedElementLite( String elementName, String codePrefix )
    {
        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, codePrefix );
    }


    protected Element createHL72CodedElementLite( String elementName, String codePrefix, String codeValue )
    {
        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElementLite( String elementName, String codePrefix, String[] aCodeValues )
    {
        String codeValue = getRandomValueFromArray( aCodeValues );
        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElementLite( String elementName, String codePrefix, String[] aCodeValues, int index )
    {
        String codeValue = aCodeValues[index];
        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElementLite( String elementName, String[][] aCodeValues, int index )
    {
        String[] codeValue = aCodeValues[index];
        Element valueCodeElement = DocumentHelper.createElement( elementName );
        valueCodeElement.addElement( "code" ).addText( codeValue[0] );
        valueCodeElement.addElement( "displayText" ).addText( codeValue[1] );
        valueCodeElement.addElement( "codingSystem" ).addText( codeValue[2] );

        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, valueCodeElement );
    }


    protected Element createHL72CodedElementLite( String elementName, Element hl72CodedElementLite )
    {
        return BaseDatatypesBuilder.createHL72CodedElementLite( elementName, hl72CodedElementLite );
    }


    protected Element createHL72CodedElement( String elementName, String codePrefix )
    {
        return BaseDatatypesBuilder.createHL72CodedElement( elementName, codePrefix );
    }


    protected Element createHL72CodedElement( String elementName, String codePrefix, String codeValue )
    {
        return BaseDatatypesBuilder.createHL72CodedElement( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElement( String elementName, String codePrefix, String[] codeValues )
    {
        String codeValue = getRandomValueFromArray( codeValues );
        return BaseDatatypesBuilder.createHL72CodedElement( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElementExtended( String elementName, String codePrefix )
    {
        return BaseDatatypesBuilder.createHL72CodedElementExtended( elementName, codePrefix );
    }


    protected Element createHL72CodedElementExtended( String elementName, String codePrefix, String codeValue )
    {
        return BaseDatatypesBuilder.createHL72CodedElementExtended( elementName, codePrefix, codeValue );
    }


    protected Element createHL72CodedElementExtended( String elementName, String codePrefix, String[] codeValues )
    {
        String codeValue = getRandomValueFromArray( codeValues );
        return BaseDatatypesBuilder.createHL72CodedElementExtended( elementName, codePrefix, codeValue );
    }


    protected Element createPractitionerParticipationLite( String elementName, String comment )
    {
        Element newHL72PersonName = createHL72PersonName( "name" );
        Element newPractitionerLite = CommonBuilder.createPractitionerLite( "practitioner", newHL72PersonName );
        return CommonBuilder.createPractitionerParticipationLite( elementName, comment, newPractitionerLite );
    }


    protected Element createComment( String elementName, String comment )
    {
        Element commentElement = DocumentHelper.createElement( elementName );
        commentElement.setText( comment );
        return commentElement;
    }


    protected List<Element> createSimpleStringElements( String elementName, String commentPrefix, int count )
    {
        List<Element> comments = new ArrayList<Element>();

        for ( int i = 0; i < count; i++ )
        {
            Element commentElement = DocumentHelper.createElement( elementName );
            commentElement.setText( String.format( "%s-%d", commentPrefix, i ) );
            comments.add( commentElement );
        }

        return comments;
    }


    protected Element createHL72PersonIdentifier( String elementName )
    {
        return BaseDatatypesBuilder.createHL72PersonIdentifier( elementName );
    }


    protected Element createHL72PersonIdentifier( String elementName, String sourcePersonId )
    {
        return BaseDatatypesBuilder.createHL72PersonIdentifier( elementName, sourcePersonId );
    }


    protected Element createHL72PersonIdentifier( String elementName, String[] sourcePersonIds )
    {
        return BaseDatatypesBuilder.createHL72PersonIdentifier( elementName, getRandomValueFromArray( sourcePersonIds ) );
    }


    protected Element createHL72PersonIdentifier( String elementName, Element hl72PersonIdentifier )
    {
        return BaseDatatypesBuilder.createHL72PersonIdentifier( elementName, hl72PersonIdentifier );
    }


    protected Element createPatientLite( String elementName )
    {
        return CommonBuilder.createPatientLite( elementName );
    }

    protected Element createPatientIdLite( String elementName )
    {
        return CommonBuilder.createPatientIdLite( elementName );
    }

    protected Element createPractitionerLite( String elementName, String[] sourcePersonIds )
    {
        return createPractitionerLite( elementName, getRandomValueFromArray( sourcePersonIds ) );
    }


    protected Element createPractitionerLite( String elementName, String sourcePersonId )
    {
        Element newPersonName = createHL72PersonName( "name" );
        Element newHL72PersonIdentifier = createHL72PersonIdentifier( "identifier", sourcePersonId );
        return CommonBuilder.createPractitionerLite( elementName, newPersonName, newHL72PersonIdentifier );
    }


    protected Element createPractitionerParticipationLite( String elementName, String sourcePersonId, String comment )
    {
        return CommonBuilder.createPractitionerParticipationLite( elementName, comment, createPractitionerLite( "practitioner", sourcePersonId ) );
    }


    protected Element createPractitionerParticipationLite( String elementName, String comment, String[] practitionerIds )
    {
        return createPractitionerParticipationLite( elementName, getRandomValueFromArray( practitionerIds ), comment );
    }


    protected Element createHL72EntityIdentifier( String elementName )
    {
        return BaseDatatypesBuilder.createHL72EntityIdentifier( elementName );
    }


    protected Element createHL72EntityIdentifier( String elementName, String entityIdentifier, String namespaceId, String universalId )
    {
        return BaseDatatypesBuilder.createHL72EntityIdentifier( elementName, entityIdentifier, namespaceId, universalId );
    }


    protected Element createHL72EntityIdentifier( String elementName, String entityIdentifier )
    {
        return BaseDatatypesBuilder.createHL72EntityIdentifier( elementName, entityIdentifier );
    }


    protected Element createHL72EntityIdentifier( String elementName, long id )
    {
        return BaseDatatypesBuilder.createHL72EntityIdentifier( elementName, id );
    }


    protected Element createHL72FacilityIdentifier( String elementName )
    {
        return BaseDatatypesBuilder.createHL72FacilityIdentifier( elementName );
    }


    protected Element createHL72FacilityIdentifier( String elementName, String namespaceId, String universalId )
    {
        return BaseDatatypesBuilder.createHL72FacilityIdentifier( elementName, namespaceId, universalId );
    }


    protected Element createHL72FacilityIdentifier( String elementName, String id )
    {
        return BaseDatatypesBuilder.createHL72FacilityIdentifier( elementName, id );
    }


    protected Element createHL72FacilityIdentifier( String elementName, long id )
    {
        return BaseDatatypesBuilder.createHL72FacilityIdentifier( elementName, id );
    }


    protected static Element createHL72LocationIdentifier( String elementName )
    {
        return BaseDatatypesBuilder.createHL72LocationIdentifier( elementName );
    }


    protected static Element createHL72LocationIdentifier( String elementName, String locationDescription )
    {
        return BaseDatatypesBuilder.createHL72LocationIdentifier( elementName, locationDescription );
    }


    protected static Element createPharmacyOrderableItem( String elementName, String itemCodePrefix, String dosageFormCodePrefix )
    {
        return CommonBuilder.createPharmacyOrderableItem( elementName, itemCodePrefix, dosageFormCodePrefix );
    }


    protected static Element createPharmacyDivision( String elementName, String divisionIdCodePrefix, String ncpdpIdCodePrefix )
    {
        return CommonBuilder.createPharmacyDivision( elementName, divisionIdCodePrefix, ncpdpIdCodePrefix );
    }


    protected Element createPointInTime( String elementName )
    {
        return BaseDatatypesBuilder.createPointInTime( elementName );
    }


    protected Element createPointInTime( String elementName, java.util.Date date )
    {
        return BaseDatatypesBuilder.createPointInTime( elementName, date );
    }


    protected Element createPointInTimeMS( String elementName, java.util.Date date )
    {
        return BaseDatatypesBuilder.createPointInTimeMS( elementName, date );
    }


    protected Element createPointInTime( String elementName, String xsdDateString )
    {
        return BaseDatatypesBuilder.createPointInTime( elementName, xsdDateString );
    }


    protected Element createFixedPointInTime( String elementName )
    {
        return BaseDatatypesBuilder.createFixedPointInTime( elementName );
    }


    protected Element createZeroToTenRating( String elementName )
    {
        return BaseDatatypesBuilder.createZeroToTenRating( elementName );
    }


    protected Element createHL72OrganizationIdentifier( String elementName )
    {
        return createHL72OrganizationIdentifier( elementName, "AssigningAuthNamespaceId", "OrganizationId", "OrganizationName" );
    }


    protected Element createHL72OrganizationIdentifier( String elementName, String assigningAuthNamespaceId, String organizationId, String aOrganizationName )
    {
        return BaseDatatypesBuilder.createHL72OrganizationIdentifier( elementName, assigningAuthNamespaceId, organizationId, aOrganizationName );
    }


    protected Element createHL72OrganizationIdentifierExtended( String elementName )
    {
        return createHL72OrganizationIdentifierExtended( elementName, "AssigningAuthNamespaceId", "OrganizationId", "OrganizationName" );
    }


    protected Element createHL72OrganizationIdentifierExtended( String elementName, String assigningAuthNamespaceId, String organizationId, String aOrganizationName )
    {
        return BaseDatatypesBuilder.createHL72OrganizationIdentifierExtended( elementName, assigningAuthNamespaceId, organizationId, aOrganizationName );
    }


    protected Element createPhysicalQuantity( String elementName )
    {
        return createPhysicalQuantity( elementName, "1.0" );
    }


    protected Element createPhysicalQuantity( String elementName, String aPhysicalQuantity )
    {
        return BaseDatatypesBuilder.createPhysicalQuantity( elementName, aPhysicalQuantity );
    }


    protected Element createMoney( String elementName )
    {
        return BaseDatatypesBuilder.createMoney( elementName );

    }


    protected Element createMoney( String elementName, String aValue )
    {
        return BaseDatatypesBuilder.createMoney( elementName, aValue );
    }


    protected String getRandomValueFromArray( String[] array )
    {
        return array[random.nextInt( array.length )];
    }


    protected String getRandomValueFromArray( String[] array, Random aRandom )
    {
        return array[aRandom.nextInt( array.length )];
    }


    protected Element createGenericJournalEntryDetails( String elementName, Element patientIdentifier, int index, boolean updateRecordXml, String xsdDateString, String recordIdentifier,
                    String attachementName )
    {
    	return createGenericJournalEntryDetails( elementName, patientIdentifier, index, updateRecordXml, xsdDateString, recordIdentifier,
    			attachementName, false);
    }

	protected Element createGenericJournalEntryDetails(String elementName, Element patientIdentifier, int index, boolean updateRecordXml, String xsdDateString, String recordIdentifier,
			String attachmentName, boolean createTwoAttachmentsWithSameName) 
	{
		Element genericJournalEntryDetailsElement = DocumentHelper.createElement(elementName);

		Element newPatient = createPatientLite("patient");
		if (patientIdentifier != null) {
			newPatient.element("identifier").element("identity").setText(patientIdentifier.elementText("identity"));
			newPatient.element("identifier").element("assigningFacility").setText(ASSIGNING_FACILITY_HDR);
			newPatient.element("identifier").element("assigningAuthority").setText(ASSIGNINGAUTHORITY_HDR);
		}
		genericJournalEntryDetailsElement.add(newPatient);

		if (updateRecordXml) {
			Element newRecordIdentifier = createHL72EntityIdentifier("recordIdentifier", recordIdentifier /* index */);
			genericJournalEntryDetailsElement.add(newRecordIdentifier);
		}

		genericJournalEntryDetailsElement.addElement("journalEntryType").addText("JournalEntryType");

		genericJournalEntryDetailsElement.addElement("allowAccessByClinicalStaff").addText("false");

		genericJournalEntryDetailsElement.addElement("comments").addText("Comments");

		// / convert from xs:date value if set, otherwise default to fixed point
		// in time date
		Element newObservationDate = xsdDateString == null || xsdDateString.trim().equals("") ? createFixedPointInTime("observationDate") : createPointInTime("observationDate", xsdDateString);

		genericJournalEntryDetailsElement.add(newObservationDate);

		// / add a small binary attachment to the document
		genericJournalEntryDetailsElement.add(createTwoAttachmentsWithSameName?createTwoBinaryAttachmentsElement(attachmentName):createBinaryAttachmentsElement(attachmentName));

		genericJournalEntryDetailsElement.addElement("dataEnterer").addText("DataEnterer");

		return genericJournalEntryDetailsElement;
	}    
    
    
    protected Element createGenericJournalEntryDetails( String elementName, Element patientIdentifier, int index, boolean updateRecordXml )
    {
        return createGenericJournalEntryDetails( elementName, patientIdentifier, index, updateRecordXml, null, null, null );
    }

    protected Element createGenericJournalEntryDetails( String elementName, Element patientIdentifier, int index, boolean updateRecordXml, boolean createTwoAttachmentsWithSameName )
    {
        return createGenericJournalEntryDetails( elementName, patientIdentifier, index, updateRecordXml, null, null, null, createTwoAttachmentsWithSameName );
    }

    protected Element createGenericJournalEntryDetailsRecordId( String elementName, Element patientIdentifier, int index, boolean updateRecordXml, String recordId )
    {
        Element genericJournalEntryDetailsElement = DocumentHelper.createElement( elementName );

        Element newPatient = createPatientLite( "patient" );
        if ( patientIdentifier != null )
        {
            newPatient.element( "identifier" ).element( "identity" ).setText( patientIdentifier.elementText( "identity" ) );
            newPatient.element( "identifier" ).element( "assigningFacility" ).setText( ASSIGNING_FACILITY_HDR );
            newPatient.element( "identifier" ).element( "assigningAuthority" ).setText( ASSIGNINGAUTHORITY_HDR );
        }
        genericJournalEntryDetailsElement.add( newPatient );

        if ( updateRecordXml )
        {
            Element element = DocumentHelper.createElement( "recordIdentifier" );
            element.addElement( "identity" ).addText( recordId );
            element.addElement( "namespaceId" ).addText( "NamespaceId" );
            element.addElement( "universalId" ).addText( "UniversalId" );
            element.addElement( "universalIdType" ).addText( "UniversalIdType" );
            genericJournalEntryDetailsElement.add( element );
        }

        genericJournalEntryDetailsElement.addElement( "journalEntryType" ).addText( "JournalEntryType" );

        genericJournalEntryDetailsElement.addElement( "allowAccessByClinicalStaff" ).addText( "false" );

        genericJournalEntryDetailsElement.addElement( "comments" ).addText( "Comments" );

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

        genericJournalEntryDetailsElement.add( createBinaryAttachmentsElement( null ) );

        genericJournalEntryDetailsElement.addElement( "dataEnterer" ).addText( "DataEnterer" );

        return genericJournalEntryDetailsElement;
    }
    


    public Element makeJournalEntry( String elementName, String recordIdentifier, String recordStatus, String clinicalDataElementName )
    {
        Element newPatientJournalEntries = DocumentHelper.createElement( elementName );
        Element newPatientJournalEntry = DocumentHelper.createElement( clinicalDataElementName );

        Element newGenericJournalEntryDetails = DocumentHelper.createElement( "genericJournalEntryDetails" );

        Element newRecordIdentifier = createHL72EntityIdentifier( "recordIdentifier", recordIdentifier );
        newGenericJournalEntryDetails.add( newRecordIdentifier );

        newGenericJournalEntryDetails.addElement( "recordStatus" ).addText( recordStatus );
        newPatientJournalEntry.add( newGenericJournalEntryDetails );
        newPatientJournalEntries.add( newPatientJournalEntry );

        return newPatientJournalEntries;
    }


    /* creates a binaryAttachments element for HA journal domains.  The intent of this method is to make 
     * binary attachments an integral part of all the HA journal domain builders, integration tests and 
     * functional tests.  To do with without creating a huge overhead, this method uploads and encodes
     * a very small image attachment.  
     * 
     */
    protected Element createBinaryAttachmentsElement( String attachmentName )
    {
        /// load image from test resources
        String hexResourceLocation = "gov/va/med/cds/ha/attachments/small-test-attachment2.jpg";
        String hexResourceName=extractResourceName(hexResourceLocation);
        String hexResourceMimeType = extractMimeType(hexResourceName);
    	
        String base64ResourceLocation = "gov/va/med/cds/ha/attachments/medium-test-attachment2.gif";
        String base64ResourceName=extractResourceName(base64ResourceLocation);
        String base64ResourceMimeType = extractMimeType(base64ResourceName);
    	
    	/// add a binary attachment element
        Element binaryAttachmentsElement = DocumentHelper.createElement( "binaryAttachments" );
        Element firstBinaryAttachmentElement = DocumentHelper.createElement( "binaryAttachment" );
        binaryAttachmentsElement.add( firstBinaryAttachmentElement );
        Element secondBinaryAttachmentElement = DocumentHelper.createElement( "binaryAttachment" );
        binaryAttachmentsElement.add( secondBinaryAttachmentElement );

        /// mime type
        Element firstMimeTypeElement = DocumentHelper.createElement( "mimeType" );
        firstMimeTypeElement.setText( hexResourceMimeType);
        firstBinaryAttachmentElement.add( firstMimeTypeElement );

        Element secondMimeTypeElement = DocumentHelper.createElement( "mimeType" );
        secondMimeTypeElement.setText( base64ResourceMimeType);
        secondBinaryAttachmentElement.add( secondMimeTypeElement );
        
        Element hexAttachmentName = DocumentHelper.createElement( "name" );
        hexAttachmentName.setText( attachmentName!=null?attachmentName:hexResourceName  );
        firstBinaryAttachmentElement.add( hexAttachmentName );
        Element secondAttachmentNameElement = DocumentHelper.createElement( "name" );
        secondAttachmentNameElement.setText( attachmentName!=null?attachmentName:base64ResourceName );
        secondBinaryAttachmentElement.add( secondAttachmentNameElement );

        Element hexBinaryAttachment = DocumentHelper.createElement( "hexBinaryAttachment" );
        Element base64BinaryAttachment = DocumentHelper.createElement( "base64BinaryAttachment" );

        try
        {
            byte[] hexBytes = StreamUtil.resourceToBytes( new ClassPathResource( hexResourceLocation ) );
            String encodedHexString = Hex.encodeHexString( hexBytes );
            hexBinaryAttachment.setText( encodedHexString );
        }
        catch ( Exception e )
        {
            String message = String.format( "Error occurred loading resource '%s': Error: %s.", hexResourceLocation, e.getMessage() );
            message += " NOTE: If running this test in an eclipse environment," + " then it may be necessary to add the src/test/resources directory to the project(s) src path so "
                            + " that JUnit can find the resource.";
            throw new IllegalStateException( message );
        }
        
        try
        {
            byte[] base64Bytes = StreamUtil.resourceToBytes( new ClassPathResource( base64ResourceLocation ) );
            String encodedBase64String = Base64.encodeBase64String(base64Bytes);
            base64BinaryAttachment.setText( encodedBase64String );
        }
        catch ( Exception e )
        {
            String message = String.format( "Error occurred loading resource '%s': Error: %s.", base64ResourceLocation, e.getMessage() );
            message += " NOTE: If running this test in an eclipse environment," + " then it may be necessary to add the src/test/resources directory to the project(s) src path so "
                            + " that JUnit can find the resource.";
            throw new IllegalStateException( message );
        }
 
        firstBinaryAttachmentElement.add( hexBinaryAttachment );
        secondBinaryAttachmentElement.add( base64BinaryAttachment );
        
        return binaryAttachmentsElement;
    }
    
    /* creates a binaryAttachments element for HA journal domains.  The intent of this method is to make 
     * binary attachments an integral part of all the HA journal domain builders, integration tests and 
     * functional tests.  To do with without creating a huge overhead, this method uploads and encodes
     * a very small image attachment.  
     * 
     */
    protected Element createBase64BinaryAttachmentsElement( String attachmentName ) 
    {
        /// add a binary attachment element
        Element binaryAttachmentsElement = DocumentHelper.createElement( "binaryAttachments" );
        Element binaryAttachmentElement = DocumentHelper.createElement( "binaryAttachment" );
        binaryAttachmentsElement.add( binaryAttachmentElement );

        /// mime type
        Element mimeTypeElement = DocumentHelper.createElement( "mimeType" );
        mimeTypeElement.setText( "image/jpg" );
        binaryAttachmentElement.add( mimeTypeElement );

        String attachmentNm = ( attachmentName != null ) ? attachmentName : "filename_" + Math.round( Math.random() * 100000000 );
        Element attachmentNameElement = DocumentHelper.createElement( "name" );
        attachmentNameElement.setText( attachmentNm );
        binaryAttachmentElement.add( attachmentNameElement );

        /// blob
        Element base64BinaryAttachment = DocumentHelper.createElement( "base64BinaryAttachment" );

        /// load image from test resources
        String resourceLocation = "gov/va/med/cds/ha/attachments/small-test-attachment.jpg";
        try
        {
            byte[] bytes = StreamUtil.resourceToBytes( new ClassPathResource( resourceLocation ) );
          	String encodedBase64String = Base64.encodeBase64String(bytes);
            base64BinaryAttachment.setText( encodedBase64String );
        }
        catch ( Exception e )
        {
            String message = String.format( "Error occurred loading resource '%s': Error: %s.", resourceLocation, e.getMessage() );
            message += " NOTE: If running this test in an eclipse environment," + " then it may be necessary to add the src/test/resources directory to the project(s) src path so "
                            + " that JUnit can find the resource.";
            throw new IllegalStateException( message );
        }
        binaryAttachmentElement.add( base64BinaryAttachment );
        return binaryAttachmentsElement;
    }

    private static String extractResourceName( String resourceLocation)
    {
    	int separatorIndex = resourceLocation.lastIndexOf("/");
    	if ( separatorIndex!=-1)
    	{
    		return resourceLocation.substring(separatorIndex+1);
    	}
    	separatorIndex= resourceLocation.lastIndexOf("\\");
    	if ( separatorIndex!=-1)
    	{
    		return resourceLocation.substring(separatorIndex+1);
    	}
    	throw new IllegalArgumentException("expecting a resourceLocation argument containing a \\ or / character");
    }

    private static String extractMimeType( String resourceName)
    {
    	String extension = resourceName.substring(resourceName.lastIndexOf(".")+1).toLowerCase().trim();
    	if ( extension.endsWith("jpg")) return "image/jpg";
    	if ( extension.endsWith("gif")) return "image/gif";
    	if ( extension.endsWith("png")) return "image/png";
    	if ( extension.endsWith("bmp")) return "image/bmp";
    	return "mimetype/" + extension;
    }

    
    protected Element createTwoBinaryAttachmentsElement( String attachmentName )
    {
        /// load image from test resources
        String hexResourceLocation = "gov/va/med/cds/ha/attachments/small-test-attachment.jpg";
        String hexResourceName=extractResourceName(hexResourceLocation);
        String hexResourceMimeType = extractMimeType(hexResourceName);
    	
        String base64ResourceLocation = "gov/va/med/cds/ha/attachments/medium-test-attachment.png";
        String base64ResourceName=extractResourceName(base64ResourceLocation);
        String base64ResourceMimeType = extractMimeType(base64ResourceName);
    	
    	/// add a binary attachment element
        Element binaryAttachmentsElement = DocumentHelper.createElement( "binaryAttachments" );
        Element firstBinaryAttachmentElement = DocumentHelper.createElement( "binaryAttachment" );
        binaryAttachmentsElement.add( firstBinaryAttachmentElement );
        Element secondBinaryAttachmentElement = DocumentHelper.createElement( "binaryAttachment" );
        binaryAttachmentsElement.add( secondBinaryAttachmentElement );

        /// mime type
        Element firstMimeTypeElement = DocumentHelper.createElement( "mimeType" );
        firstMimeTypeElement.setText( hexResourceMimeType);
        firstBinaryAttachmentElement.add( firstMimeTypeElement );

        Element secondMimeTypeElement = DocumentHelper.createElement( "mimeType" );
        secondMimeTypeElement.setText( base64ResourceMimeType);
        secondBinaryAttachmentElement.add( secondMimeTypeElement );
        
        Element hexAttachmentName = DocumentHelper.createElement( "name" );
        hexAttachmentName.setText( attachmentName!=null?attachmentName:hexResourceName  );
        firstBinaryAttachmentElement.add( hexAttachmentName );
        Element secondAttachmentNameElement = DocumentHelper.createElement( "name" );
        secondAttachmentNameElement.setText( attachmentName!=null?attachmentName:base64ResourceName );
        secondBinaryAttachmentElement.add( secondAttachmentNameElement );

        Element hexBinaryAttachment = DocumentHelper.createElement( "hexBinaryAttachment" );
        Element base64BinaryAttachment = DocumentHelper.createElement( "base64BinaryAttachment" );

        try
        {
            byte[] hexBytes = StreamUtil.resourceToBytes( new ClassPathResource( hexResourceLocation ) );
            String encodedHexString = Hex.encodeHexString( hexBytes );
            hexBinaryAttachment.setText( encodedHexString );
        }
        catch ( Exception e )
        {
            String message = String.format( "Error occurred loading resource '%s': Error: %s.", hexResourceLocation, e.getMessage() );
            message += " NOTE: If running this test in an eclipse environment," + " then it may be necessary to add the src/test/resources directory to the project(s) src path so "
                            + " that JUnit can find the resource.";
            throw new IllegalStateException( message );
        }
        
        try
        {
            byte[] base64Bytes = StreamUtil.resourceToBytes( new ClassPathResource( base64ResourceLocation ) );
            String encodedBase64String = Base64.encodeBase64String(base64Bytes);
            base64BinaryAttachment.setText( encodedBase64String );
        }
        catch ( Exception e )
        {
            String message = String.format( "Error occurred loading resource '%s': Error: %s.", base64ResourceLocation, e.getMessage() );
            message += " NOTE: If running this test in an eclipse environment," + " then it may be necessary to add the src/test/resources directory to the project(s) src path so "
                            + " that JUnit can find the resource.";
            throw new IllegalStateException( message );
        }
 
        firstBinaryAttachmentElement.add( hexBinaryAttachment );
        secondBinaryAttachmentElement.add( base64BinaryAttachment );
        
        return binaryAttachmentsElement;
    }

}
