

package gov.va.med.cds.util;


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

import java.util.List;
import java.util.Map;


public class NestedElementWrapperUtil
{
    @SuppressWarnings( "rawtypes" )
    Map<String, Map> nestedElementsMap;

    private static final String IC_CREATE_TEMPLATE_ID = "XXXIntoleranceConditionCreateOrUpdate40060";
    private static final String COMMENT_EVENTS = "commentEvents";
    private static final String COMMENTS = "comments";
    
    private static final String CURRENT_PROVIDER_COMMENTS = "currentProviderComments";
    private static final String OBSERVATION_METHODS = "observationMethods";
    private static final String REFILL_DISPENSE_COMMENTS_XPATH = "//outpatientMedicationPromises/refillDispense/comments";
    private static final String PARTIAL_DISPENSE_COMMENTS_XPATH = "//outpatientMedicationPromises/partialDispense/comments";
    private static final String REFILL_DISPENSE_CURRENT_PROVIDER_COMMENTS_XPATH = "//outpatientMedicationPromises/refillDispense/currentProviderComments";
    private static final String PARTIAL_DISPENSE_CURRENT_PROVIDER_COMMENTS_XPATH = "//outpatientMedicationPromises/partialDispense/currentProviderComments";
    
    private static final String CHEMISTRY_RESULTS = "chemistryResults";
    private static final String LABCOMMENT_EVENTS = "labCommentEvents";
    private static final String LABTESTPROMISES_LABCOMMENTEVENTS_COMMENTS_XPATH = "//labTestPromises/labCommentEvents/comments";
    private static final String LABTESTPROMISES_LABTESTS_CHEM_RESULTS_COMMENTS_XPATH = "//labTestPromises/labTests/chemistryResults/labCommentEvents/comments";
    private static final String LABTESTPROMISES_LABTESTS_CHEM_RESULTS_LABCOMMENTEVENTS_XPATH = "//labTestPromises/labTests/chemistryResults/labCommentEvents";
    private static final String LABTESTPROMISES_LABTESTS_CHEM_RESULTS_OBSERVATIONMETHODS_XPATH = "//labTestPromises/labTests/chemistryResults/observationMethods";
    private static final String LABTESTPROMISES_LABTESTS_CHEM_RESULTS_XPATH = "//labTestPromises/labTests/chemistryResults";


    @SuppressWarnings( "unchecked" )
    public Document addNestedElements( Document clinicalDataDocument, String templateId )
    {
        Map<String, String> elements = nestedElementsMap.get( templateId );

        if ( null == elements || elements.size() == 0 )
        {
            return clinicalDataDocument;
        }

        Element wrappedElement = null;
        Element wrappedInnerElement = null;
        List<Element> filteredElements = null;
        List<Element> innerElements = null;
        Element parent = null;
        for ( String xpath : elements.keySet() )
        {
            if ( xpath.equals( LABTESTPROMISES_LABCOMMENTEVENTS_COMMENTS_XPATH )
                            || xpath.equals( LABTESTPROMISES_LABTESTS_CHEM_RESULTS_COMMENTS_XPATH ) )
            {
                Element commentsElement = ( Element )clinicalDataDocument.selectSingleNode( xpath );
                if ( commentsElement != null )
                {
                    Element commentsParent = commentsElement.getParent();
                    filteredElements = clinicalDataDocument.selectNodes( commentsParent.getPath() );
                    for ( Element element : filteredElements )
                    {
                        wrappedElement = DocumentHelper.createElement( COMMENTS );
                        innerElements = element.selectNodes( COMMENTS );
                        for ( Element ie : innerElements )
                        {
                            wrappedElement.add( ie.detach() );
                        }
                        element.add( wrappedElement );
                    }
                }
            }
            else if ( xpath.equals( LABTESTPROMISES_LABTESTS_CHEM_RESULTS_OBSERVATIONMETHODS_XPATH ) )
            {
                Element commentsElement = ( Element )clinicalDataDocument.selectSingleNode( xpath );
                if ( commentsElement != null )
                {
                    Element commentsParent = commentsElement.getParent();
                    filteredElements = clinicalDataDocument.selectNodes( commentsParent.getPath() );
                    for ( Element element : filteredElements )
                    {
                        wrappedElement = DocumentHelper.createElement( OBSERVATION_METHODS );
                        innerElements = element.selectNodes( OBSERVATION_METHODS );
                        for ( Element ie : innerElements )
                        {
                            wrappedElement.add( ie.detach() );
                        }
                        element.add( wrappedElement );
                    }
                }
            }
            else if ( xpath.equals( LABTESTPROMISES_LABTESTS_CHEM_RESULTS_LABCOMMENTEVENTS_XPATH ) )
            {
                Element commentsElement = ( Element )clinicalDataDocument.selectSingleNode( xpath );
                if ( commentsElement != null )
                {
                    Element commentsParent = commentsElement.getParent();
                    filteredElements = clinicalDataDocument.selectNodes( commentsParent.getPath() );
                    for ( Element element : filteredElements )
                    {
                        wrappedElement = DocumentHelper.createElement( LABCOMMENT_EVENTS );
                        innerElements = element.selectNodes( LABCOMMENT_EVENTS );
                        for ( Element ie : innerElements )
                        {
                            wrappedElement.add( ie.detach() );
                        }
                        element.add( wrappedElement );
                    }
                }
            }
            else if ( xpath.equals( LABTESTPROMISES_LABTESTS_CHEM_RESULTS_XPATH ) )
            {
                Element commentsElement = ( Element )clinicalDataDocument.selectSingleNode( xpath );
                if ( commentsElement != null )
                {
                    Element commentsParent = commentsElement.getParent();
                    filteredElements = clinicalDataDocument.selectNodes( commentsParent.getPath() );
                    for ( Element element : filteredElements )
                    {
                        wrappedElement = DocumentHelper.createElement( CHEMISTRY_RESULTS );
                        innerElements = element.selectNodes( CHEMISTRY_RESULTS );
                        for ( Element ie : innerElements )
                        {
                            wrappedElement.add( ie.detach() );
                        }
                        element.add( wrappedElement );
                    }
                }
            }
            else
            {
                filteredElements = clinicalDataDocument.selectNodes( xpath );
                wrappedElement = DocumentHelper.createElement( elements.get( xpath ) );

                for ( Element element : filteredElements )
                {
                    if ( templateId.equals( IC_CREATE_TEMPLATE_ID ) && element.getName().equals( COMMENT_EVENTS ) )
                    {
                        wrappedInnerElement = DocumentHelper.createElement( COMMENTS );
                        innerElements = element.selectNodes( element.getUniquePath() + "/" + COMMENTS );

                        for ( Element el : innerElements )
                        {
                            parent = el.getParent();
                            el.detach();
                            wrappedInnerElement.add( el );
                        }
                        element.add( wrappedInnerElement );
                    }

                    parent = element.getParent();
                    element.detach();

                    wrappedElement.add( element );
                }

                if ( null != parent )
                    parent.add( wrappedElement );
            }
        }

        return clinicalDataDocument;
    }


    @SuppressWarnings( "rawtypes" )
    public void setNestedElementsMap( Map<String, Map> nestedElementsMap )
    {
        this.nestedElementsMap = nestedElementsMap;
    }
}
