

package gov.va.med.cds.response.strategy;


import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.persistence.PersistenceException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;


public class ClinicalRemindersBlobStrategy
    extends
        ReferenceMappingVistaResponseBlobStrategy
{

    private static String SKIP_ELEMENT_CREATION = "SKIP_ELEMENT_CREATION";
    private Map<String, String> clinicalRemindersResponseXmlStructure;
    private Map<String, String> clinicalRemindersVistaResponseMetaData;

    /***
     * 
     */
    @Override
    public Element formatResponse( List<Map<String, Object>> resultList, String domainEntryPoint, String templateId )
        throws Exception
    {
        resultList = formatResultList( resultList );

        Element results = DocumentHelper.createElement( "results" );
        Element record = DocumentHelper.createElement( "clinicalReminder" );
        List<Node> nodeList = null;
        Map<String, Object> nextEntry = null;
        Document refDoc = null;
        Element ele = null;
        
        int i = 1;
        for ( Map<String, Object> map : resultList )
        {

            refDoc = getRefDocument( domainEntryPoint, templateId );
            treeWalk( refDoc.getRootElement(), map );
            for ( String elementName : clinicalRemindersResponseXmlStructure.keySet() )
            {
                nodeList = refDoc.selectNodes( clinicalRemindersResponseXmlStructure.get( elementName ) );
                if ( record.element( elementName ) == null )
                {
                    for ( Node addNode : nodeList )
                    {

                        if ( elementName.startsWith( SKIP_ELEMENT_CREATION ) )
                        {
                            record.add( addNode.detach() );
                        }
                        else
                        {
                            record.addElement( elementName ).add( addNode.detach() );
                        }
                    }
                }
                else
                {
                    ele = record.element( elementName );
                    for ( Node addNode : nodeList )
                    {
                        ele.add( addNode.detach() );
                    }
                }
            }

            if ( i < resultList.size() )
            {
                nextEntry = resultList.get( i );
                if ( nextEntry.containsKey( "IEN" ) )
                {
                    createResponse( results, record );

                }
            }
            else if ( i == resultList.size() )
            {
                createResponse( results, record );
            }

            i++ ;

        }

        return results;
    }


    private void createResponse( Element results, Element record )
    {

        Element clinicalReminder = DocumentHelper.createElement( "clinicalReminder" );
        List<Node> nodeList = record.elements();
        for ( Node addNode : nodeList )
        {
            clinicalReminder.add( addNode.detach() );
        }
        results.add( clinicalReminder );
        record.clearContent();
    }


    protected List<Map<String, Object>> formatResultList( List<Map<String, Object>> resultList )
        throws IOException
    {
        Document storedProcResult = null;
        String readLine = null;
        StringBuffer response = new StringBuffer();
        BufferedReader reader = new BufferedReader( new InputStreamReader( new java.io.ByteArrayInputStream( ( byte[] )resultList.get( 0 ).get( "stream" ) ) ) );

        do
        {
            readLine = reader.readLine();
            if ( readLine != null )
            {
                response = response.append( readLine );
            }
        }
        while ( readLine != null );

        List<Map<String, Object>> buildResultList = new ArrayList<Map<String, Object>>();

        try
        {
            storedProcResult = DocumentHelper.parseText( "<results>" + response.toString() + "</results>" );
        }
        catch ( DocumentException e )
        {
            throw new PersistenceException( ErrorCodeEnum.DOC_PARSER_DOM_EXCEPTION, e, e.getMessage() );
        }

        buildResultList = getResults( resultList, storedProcResult, buildResultList );

        return buildResultList;
    }


    private List<Map<String, Object>> getResults( List<Map<String, Object>> resultList, Document storedProcResult,
                    List<Map<String, Object>> buildResultList )
    {
        String valueAsString = null;
        Element colElement = null;
        Scanner valueScanner = null;
        Scanner columnNameScanner = null;
        String colName = null;
        String colValue = null;
        Map<String, Object> newRowMap = null;

        String innerValueAsString = null;
        Scanner innerValueScanner = null;
        Scanner innerColumnNameScanner = null;
        String innerColName = null;
        String innerColValue = null;
        Element innerElementContainingColumnNames = null;
        String innerColumnNameAsString = null;
        List<Element> innerColElements = null;
        Map<String, Object> innerRowMap = null;

        Element elementContainingColumnNames = storedProcResult.getRootElement().element( clinicalRemindersVistaResponseMetaData.get( "outerDef" ) ).element( clinicalRemindersVistaResponseMetaData.get( "columnDef" ) );
        String columnNameAsString = elementContainingColumnNames.getText();
        List<Element> dataElements = storedProcResult.getRootElement().elements( clinicalRemindersVistaResponseMetaData.get( "outerTag" ) );
        int i = 0;
        if ( dataElements.size() > 0 )
        {
            for ( Element dataElementValue : dataElements )
            {
                colElement = ( Element )dataElementValue.selectSingleNode( clinicalRemindersVistaResponseMetaData.get( "columnTag" ) );

                newRowMap = new HashMap<String, Object>();
                valueAsString = colElement.getText();
                if ( valueAsString.length() > 0 )
                {
                    valueScanner = new Scanner( valueAsString ).useDelimiter( "\\^" );
                    columnNameScanner = new Scanner( columnNameAsString ).useDelimiter( "\\^" );
                    while ( valueScanner.hasNext() )
                    {
                        colName = columnNameScanner.next();
                        colValue = valueScanner.next();

                        if ( ( colName != null && colName.length() > 0 ) && ( colValue != null && colValue.length() > 0 ) )
                        {
                            newRowMap.put( colName, colValue );
                        }
                    }
                    buildResultList.add( newRowMap );
                }

                innerElementContainingColumnNames = storedProcResult.getRootElement().element( clinicalRemindersVistaResponseMetaData.get( "outerDef" ) ).element( clinicalRemindersVistaResponseMetaData.get( "dtlColumnDef" ) );
                innerColumnNameAsString = innerElementContainingColumnNames.getText();
                innerColElements = dataElementValue.selectNodes( clinicalRemindersVistaResponseMetaData.get( "dtlColumnTag" ) );
                for ( Element innerColElement : innerColElements )
                {
                    innerRowMap = new HashMap<String, Object>();
                    innerValueAsString = innerColElement.getText();

                    if ( innerValueAsString.length() > 0 )
                    {
                        innerValueScanner = new Scanner( innerValueAsString ).useDelimiter( "\\^" );
                        innerColumnNameScanner = new Scanner( innerColumnNameAsString ).useDelimiter( "\\^" );

                        while ( innerValueScanner.hasNext() )
                        {
                            innerColName = innerColumnNameScanner.next();
                            innerColValue = innerValueScanner.next();

                            if ( ( innerColName != null && innerColName.length() > 0 ) && ( innerColValue != null && innerColValue.length() > 0 ) )
                            {
                                innerRowMap.put( innerColName, innerColValue );
                            }
                        }

                    }
                    buildResultList.add( innerRowMap );
                }
                i++;
            }
        }
        buildResultList.get( 0 ).put( "SITE ID", ( String )resultList.get( 0 ).get( "siteID" ) );
        buildResultList.get( 0 ).put( "USVHA", "USVHA" );

        return buildResultList;
    }

    public void setClinicalRemindersVistaResponseMetaData( Map<String, String> clinicalRemindersVistaResponseMetaData )
    {
        this.clinicalRemindersVistaResponseMetaData = clinicalRemindersVistaResponseMetaData;
    }

    public void setClinicalRemindersResponseXmlStructure( Map<String, String> clinicalRemindersResponseXmlStructure )
    {
        this.clinicalRemindersResponseXmlStructure = clinicalRemindersResponseXmlStructure;
    }

}
