/*******************************************************************************
 *  Copyright 2017 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *    http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.hl7282.baselibs.messagedictionary;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import cdac.medinfo.sdk.hl7282.exceptions.InvalidDictionaryException;
import cdac.medinfo.sdk.hl7282.utils.EnumHL7System;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageCode;
import cdac.medinfo.sdk.hl7282.utils.EnumSegmentCardinality;
import cdac.medinfo.sdk.hl7282.utils.EnumSegments;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.HL7Logger;
import cdac.medinfo.sdk.hl7282.utils.IMap;
import cdac.medinfo.sdk.hl7282.utils.ISegmentItem;

/**
 * XML Handler class provides java dependent implementation of XML File parsing mechanism.
 */
class MessageXMLHandler 
{
	
	String strXmlfile=null;
	String strNodeNameValue ="name";
	String strCardinality ="cardinality";
	String strSegmentName = "Segment";
	String strGroup ="Group";
	String strHl7Group ="HL7_GROUP_";
	String strHL7Seg ="HL7_SEG_";
	String strValue ="value";

	private void populateCode(Node objCodeNode,EnumHL7System objEnumHL7System,MessageDictionary objMessageDictionary)
	{
		NamedNodeMap objCodeNamedNodeMap = objCodeNode.getAttributes();
		String strCode = objCodeNamedNodeMap.getNamedItem(strNodeNameValue).getNodeValue();

		NodeList objEventNodeList = objCodeNode.getChildNodes();
		for(int iEvent=0;iEvent<objEventNodeList.getLength();iEvent++)
		{
			Node objEventNode =  objEventNodeList.item(iEvent);
			if(objEventNode.getNodeType() == Node.ELEMENT_NODE)
			{
				NamedNodeMap objEventNamedNodeMap = objEventNode.getAttributes();
				String strEvent = objEventNamedNodeMap.getNamedItem(strNodeNameValue).getNodeValue();
				IMap objMessageMap = new Map();
				FillMessageMap(objMessageMap, objEventNode);
				objMessageDictionary.addMessageMap(strCode+"_"+strEvent, objMessageMap);
				objMessageDictionary.addPopulatedSysetm(objEnumHL7System);
			}
		}
	}

	/**
	 * The method provides java way of parsing xml file and populating dictionary.
	 * @param objDataDictionary object of DataDictionary. 
	 */
	void populate(String strXmlFile,EnumHL7System objEnumHL7System,MessageDictionary objMessageDictionary) throws InvalidDictionaryException
	{
		try
		{	
			URL objURL = MessageXMLHandler.class.getResource(strXmlFile);
			URLConnection objJarURLConnection = objURL.openConnection();

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(objJarURLConnection.getInputStream());

			NodeList objSystemCodeNodeList = doc.getElementsByTagName(MessageXMLNodes.SYSTEM.getValue());
			for(int iSystemCode=0;iSystemCode<objSystemCodeNodeList.getLength();iSystemCode++)
			{
				Node objSystemCodeNode =  objSystemCodeNodeList.item(iSystemCode);
				NamedNodeMap objSystemCodeNamedNodeMap = objSystemCodeNode.getAttributes();
				String strSystemCode = objSystemCodeNamedNodeMap.getNamedItem(strNodeNameValue).getNodeValue();
				if(objEnumHL7System.getValue().equals(strSystemCode))
				{
					NodeList objCodeNodeList = objSystemCodeNode.getChildNodes();

					for(int iCode=0;iCode<objCodeNodeList.getLength();iCode++)
					{
						Node objCodeNode =  objCodeNodeList.item(iCode);
						if(objCodeNode.getNodeType() == Node.ELEMENT_NODE)
							populateCode(objCodeNode,objEnumHL7System,objMessageDictionary);
					}
				}	
			}
		}
		catch(FileNotFoundException fnfe)
		{
			if(HL7Config.createInstance().isLoggingOn())
			{
				HL7Logger.getLogger().log(fnfe.getMessage());
			}
			throw new InvalidDictionaryException(fnfe);
		} catch (ParserConfigurationException e) 
		{
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	void FillMessageMap(IMap objMessageMap , Node objMapNode)
	{
		NodeList objSegmentNodeList = objMapNode.getChildNodes();
		for(int iSegment=0;iSegment<objSegmentNodeList.getLength();iSegment++)
		{
			Node objSegmentNode =  objSegmentNodeList.item(iSegment);
			if(objSegmentNode.getNodeType() == Node.ELEMENT_NODE)
			{
				NamedNodeMap objSegmentNamedNodeMap = objSegmentNode.getAttributes();
				String strNodeName = objSegmentNode.getNodeName();
				String strSegment = objSegmentNamedNodeMap.getNamedItem(strNodeNameValue).getNodeValue();
				String strSegmentCardinality = objSegmentNamedNodeMap.getNamedItem(strCardinality).getNodeValue();
				if(strSegmentName.equalsIgnoreCase(strNodeName))
				{
					ISegmentItem objSegmentItem = new SegmentItem();
					EnumSegmentCardinality enumSegmentCardinality = EnumSegmentCardinality.valueOf(strSegmentCardinality.toUpperCase());
					EnumSegments enumSegments = EnumSegments.valueOf(strHL7Seg+strSegment);
					objSegmentItem.setSegmentCardinality(enumSegmentCardinality);
					objSegmentItem.setName(enumSegments);
					objMessageMap.addSegmentItem(objSegmentItem);	
				}
				else if(strGroup.equalsIgnoreCase(strNodeName))
				{
					SegmentItem objSegmentItem = new SegmentItem();
					EnumSegmentCardinality enumSegmentCardinality = EnumSegmentCardinality.valueOf(strSegmentCardinality.toUpperCase());
					EnumSegments enumSegments = EnumSegments.valueOf(strHl7Group+strSegment);
					objSegmentItem.setSegmentCardinality(enumSegmentCardinality);
					objSegmentItem.setName(enumSegments);
					objSegmentItem.setIsGroup(true);
					objMessageMap.addSegmentItem(objSegmentItem);	
					IMap objGroupMessageMap = new Map();
					FillMessageMap(objGroupMessageMap , objSegmentNode);
					objSegmentItem.setGroupItems(objGroupMessageMap);
				}
			}
		}
	}

	/**
	 * 
	 * @param strXmlFile
	 * @param objMessageDictionary
	 * @throws InvalidDictionaryException
	 */
	void populateAcknowledgment(URL objURL,MessageDictionary objMessageDictionary) throws InvalidDictionaryException
	{
		try
		{
			//URL objURL = new URL(strXmlFile);
			URLConnection objJarURLConnection = objURL.openConnection();

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(objJarURLConnection.getInputStream());

			NodeList objNodeList = doc.getChildNodes().item(0).getChildNodes();
			for(int iNode=0;iNode<objNodeList.getLength();iNode++)
			{
				Node objNode = objNodeList.item(iNode);
				if(MessageXMLNodes.CODE.getValue().equalsIgnoreCase(objNode.getNodeName()))
				{
					NamedNodeMap objCodeNamedNodeMap = objNode.getAttributes();
					String strCode = objCodeNamedNodeMap.getNamedItem(strNodeNameValue).getNodeValue();
					if(EnumMessageCode.ACK.getValue().equalsIgnoreCase(strCode))
					{
						if(objNode.getNodeType() == Node.ELEMENT_NODE)
						{
							IMap objMessageMap = new Map();
							FillMessageMap(objMessageMap, objNode);
							objMessageDictionary.addMessageMap(strCode, objMessageMap);
						}
					}
				}
			}
		}
		catch(FileNotFoundException fnfe)
		{
			if(HL7Config.createInstance().isLoggingOn())
			{
				HL7Logger.getLogger().log(fnfe.getMessage());
			}
			throw new InvalidDictionaryException(fnfe);
		} 
		catch (ParserConfigurationException e) 
		{
			e.printStackTrace();
		} 
		catch (SAXException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}


	/**
	 * This method provides the value of the Node passed to it.
	 * @param attrNode object of Node.
	 * @return String - string value of a node.
	 */
	String getValueAttribute(Node attrNode)
	{
		NamedNodeMap objNamedNodeMap = attrNode.getAttributes();
		Node objNode = objNamedNodeMap.getNamedItem(strValue);
		return objNode.getNodeValue();
	}
}

