/**
 * 
 */


package gov.va.med.cds.clinicaldata.vhim400;


import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;


/**
 * @author DNS   egberb
 *
 */
public class ConfigurableClinicalDataResponse
    implements
        ClinicalDataResponseInterface
{
    private static final String DEFAULT_TEMPLATE_ID_ELEMENT_NAME = "templateId";

    private static final String DEFAULT_REQUEST_ID_ELEMENT_NAME = "requestId";

    private static final String DEFAULT_REQUESTED_NATIONAL_ID_ELEMENT_NAME = "requestedNationalId";

    private static final String DEFAULT_REQUESTED_EDIPI_ELEMENT_NAME = "requestedEdiPi";

    private static final String DEFAULT_RESULTANT_IDENTIFIERS_ELEMENT_NAME = "resultantIdentifiers";

    private static final String DEFAULT_REQUESTED_RESOLVED_IDENTIFIERS_ELEMENT_NAME = "requestedResolvedIdentifiers";

    private static final String DEFAULT_REQUESTED_EXCLUDED_IDENTIFIERS_ELEMENT_NAME = "requestedExcludedIdentifiers";

    private static final String DEFAULT_CREATED_IDENTIFIERS_ELEMENT_NAME = "recordIdentifiers";

    protected String templateIdElementName = DEFAULT_TEMPLATE_ID_ELEMENT_NAME;

    protected String requestIdElementName = DEFAULT_REQUEST_ID_ELEMENT_NAME;

    private String requestedNationalIdElementName = DEFAULT_REQUESTED_NATIONAL_ID_ELEMENT_NAME;

    private String resultantIdentifiersElementName = DEFAULT_RESULTANT_IDENTIFIERS_ELEMENT_NAME;

    private String requestedResolvedIdentifiersElementName = DEFAULT_REQUESTED_RESOLVED_IDENTIFIERS_ELEMENT_NAME;

    private String requestedEdipiElementName = DEFAULT_REQUESTED_EDIPI_ELEMENT_NAME;

    private String requestedExcludedIdentifiersElementName = DEFAULT_REQUESTED_EXCLUDED_IDENTIFIERS_ELEMENT_NAME;
    
    private String createdIdentifiersElementName = DEFAULT_CREATED_IDENTIFIERS_ELEMENT_NAME;
    
    protected static final String CLIENT_NAME_ELEMENT_NAME = "clientName";
    
    protected static final String CLIENT_REQUEST_INITIATION_TIME_ELEMENT_NAME = "clientRequestInitiationTime";

    protected String patientElementPath;

    private String clinicalRootPath;

    private String errorResponseTemplateId;


    public ConfigurableClinicalDataResponse( String patientElementPath, String clinicalRootPath, String errorResponseTemplateId )
    {
        this.patientElementPath = patientElementPath;
        this.clinicalRootPath = clinicalRootPath;
        this.errorResponseTemplateId = errorResponseTemplateId;
    }
    
    public ConfigurableClinicalDataResponse(String clinicalRootPath, String errorResponseTemplateId )
    {
        this.clinicalRootPath = clinicalRootPath;
        this.errorResponseTemplateId = errorResponseTemplateId;
    }

    public Document buildEmptyClinicalDocument( String templateId, String requestId, String clientName )
    {
    	
        Document document = buildClinicalDocument( templateId, requestId, clientName, true );
        getChildElement( document, clinicalRootPath, true );
        return document;
    }

    public Document buildEmptyClinicalDocument( String templateId, String requestId )
    {
        Document document = buildClinicalDocument( templateId, requestId, true );
        getChildElement( document, clinicalRootPath, true );
        return document;
    }


    public Document buildEmptyClinicalDocument( String templateId, String requestId, boolean addPatient )
    {
        Document document = buildClinicalDocument( templateId, requestId, addPatient );
        getChildElement( document, clinicalRootPath, addPatient );
        return document;
    }


    @Override
    public Element getChildElement( Document document, String name, boolean create )
    {
        Element rootElement = null;
        if ( document == null || ( rootElement = document.getRootElement() ) == null )
        {
            throw new IllegalArgumentException( "The document not be null and must have a root element attached." );
        }

        return getChildElement( rootElement, name, create );
    }
    
    @Override
    public Element buildRecordIdentifierElement( String recordIdentifier, Element clinicalData )
    {
        Element identifierElement = DocumentHelper.createElement( "recordIdentifier" );
        identifierElement.add(DocumentHelper.createElement("identity"));
        identifierElement.element( "identity" ).setText( recordIdentifier );
        return identifierElement;
    }


    protected Element getChildElement( Element start, String name, boolean create )
    {
        String[] pathTokens = name.split( "\\/" );
        Element parent = start;
        Element child = null;

        for ( String elementName : pathTokens )
        {
            if ( parent == null )
            {
                return null;
            }

            child = parent.element( elementName );
            if ( child == null && create )
            {
                child = DocumentHelper.createElement( elementName );
                parent.add( child );
            }

            parent = child;
        }

        return child;
    }


    @Override
    public Element getChildElement( Document document, String name )
    {
        return getChildElement( document, name, false );
    }


    @Override
    public Element getClinicalRoot( Document document )
    {
        return getChildElement( document, this.clinicalRootPath, true );
    }
    
    protected Document buildClinicalDocument( String templateId, String requestId, String clientName, boolean addPatient )
    {
        Namespace clinicalDataNamespace = DocumentHelper.createNamespace( "clinicaldata", "Clinicaldata" );
        Element clinicalDataElement = DocumentHelper.createElement( DocumentHelper.createQName( "ClinicalData", clinicalDataNamespace ) );

        if ( clientName != null )
        {
            getChildElement( clinicalDataElement, CLIENT_NAME_ELEMENT_NAME, true ).addText( clientName );
            getChildElement( clinicalDataElement, CLIENT_REQUEST_INITIATION_TIME_ELEMENT_NAME, true ).addText( "2012-12-17T09:30:47Z" );
        }
        
        if ( templateId != null )
        {
            getChildElement( clinicalDataElement, templateIdElementName, true ).addText( templateId );
        }

        if ( requestId != null )
        {
            getChildElement( clinicalDataElement, requestIdElementName, true ).addText( requestId );
        }
       
        if ( addPatient )
        {
            getChildElement( clinicalDataElement, this.patientElementPath, true );
        }

        return DocumentHelper.createDocument( clinicalDataElement );
    }


    protected Document buildClinicalDocument( String templateId, String requestId, boolean addPatient )
    {
        Namespace clinicalDataNamespace = DocumentHelper.createNamespace( "clinicaldata", "Clinicaldata" );
        Element clinicalDataElement = DocumentHelper.createElement( DocumentHelper.createQName( "ClinicalData", clinicalDataNamespace ) );

        if ( templateId != null )
        {

            getChildElement( clinicalDataElement, templateIdElementName, true ).addText( templateId );
        }

        if ( requestId != null )
        {
            getChildElement( clinicalDataElement, requestIdElementName, true ).addText( requestId );
        }

        if ( addPatient )
        {
            getChildElement( clinicalDataElement, this.patientElementPath, true );
        }

        return DocumentHelper.createDocument( clinicalDataElement );
    }


    @Override
    public Element getPatientElement( Document document )
    {
        return getChildElement( document, this.patientElementPath, true );
    }


    @Override
    public Element getRequestId( Document document )
    {
        return getChildElement( document, "requestId" );
    }


    @Override
    public Element getTemplateId( Document document )
    {
        return getChildElement( document, "templateId" );
    }


    @Override
    public Element setTemplateIdText( Document document, String templateIdText )
    {
        Element templateId = getChildElement( document, "templateId", true );
        templateId.setText( templateIdText );
        return templateId;
    }


    public Document buildEmptyClinicalDocumentWithPatient( String templateId, String requestId )
    {
        return buildClinicalDocument( templateId, requestId, true );
    }


    public Document buildEmptyClinicalDocumentWithoutPatient( String templateId, String requestId )
    {
        return buildClinicalDocument( templateId, requestId, false );
    }


    @Override
    public Element getErrorSectionRoot( Document document )
    {
        return getChildElement( document, "errorSection" );
    }


    @Override
    public String getErrorResponseTemplateId( )
    {
        return this.errorResponseTemplateId;
    }


    @Override
    public Element getRequestedNationalId( Document document )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.requestedNationalIdElementName );
        return getChildElement( document, requestIdPath );
    }


    @Override
    public Document addRequestedNationalId( Document document, String nationalId )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.requestedNationalIdElementName );
        Element requestedNationalId = getChildElement( document, requestIdPath, true );
        requestedNationalId.setText( nationalId );
        return document;
    }


    public Document buildEmptyClinicalDocument( )
    {
        return buildEmptyClinicalDocument( null, null );
    }


    public Document buildEmptyClinicalDocumentWithPatient( )
    {
        return buildClinicalDocument( null, null, true );
    }


    public Document buildClinicalDocumentWithCreatedIdentifiers( String templateId, String requestId, List<Element> createdIdentifiers, boolean addPatient )
    {

        return buildResponseClinicalDocumentWithCreatedIdentifiers( templateId, requestId, createdIdentifiers, addPatient);
    }


    public Document buildClinicalDocumentWithCreatedIdentifiers( String templateId, String requestId, List<Element> createdIdentifiers )
    {
        return buildResponseClinicalDocumentWithCreatedIdentifiers( templateId, requestId, createdIdentifiers, true );

    }


    private Document buildResponseClinicalDocumentWithCreatedIdentifiers( String templateId, String requestId, List<Element> createdIdentifiers,
                    boolean addPatient )
    {
        Document clinicalDocument = buildEmptyClinicalDocument( templateId, requestId, addPatient );
        Element clinicalDataElement = clinicalDocument.getRootElement();

        Element createdRecordIdentifiers = DocumentHelper.createElement( this.createdIdentifiersElementName );

        for ( Element identifier : createdIdentifiers )
        {
            if ( identifier != null )
            {
                createdRecordIdentifiers.add( identifier );
            }
        }

        clinicalDataElement.add( createdRecordIdentifiers );

        return clinicalDocument;
    }


    @Override
    public Element getRequestedExcludedIdentifiers( Document document )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.requestedExcludedIdentifiersElementName );
        return getChildElement( document, requestIdPath );
    }


    @Override
    public Element getRequestedResolvedIdentifiers( Document document )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.requestedResolvedIdentifiersElementName );
        return getChildElement( document, requestIdPath );
    }


    @Override
    public Element getRequestedEdipi( Document document )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.requestedEdipiElementName );
        return getChildElement( document, requestIdPath );
    }


    @Override
    public Element getResultantIdentifiers( Document document )
    {
        String requestIdPath = String.format( "%s/%s", this.patientElementPath, this.resultantIdentifiersElementName );
        return getChildElement( document, requestIdPath );
    }
    
    
    public void setCreatedIdentifiersElementName( String createdIdentifiersElementName )
    {
        this.createdIdentifiersElementName = createdIdentifiersElementName;
    }
    
    @Override
    public Document buildErrorResponse( String templateId, String requestId, Document writeResultDocument, Document clinicalDataDocument )
    {
        return writeResultDocument;
    }
   

}
