package com.tandbergtv.metadatamanager.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Intended to contains handy methods for xml file parsing/extraction etc.
 * 
 * @author spuranik
 * 
 */
public class XmlUtil {

	private static NamespaceContext ctx = new NamespaceContext() {
		public String getNamespaceURI(String prefix) {
			String uri;
			if (prefix.equals("tns"))
				uri = "http://www.tandbergtv.com/TTVSchema";
			else
				uri = null;
			return uri;
		}

		// Dummy implementation - not used!
		@SuppressWarnings("unchecked")
		public Iterator getPrefixes(String val) {
			return null;
		}

		// Dummy implemenation - not used!
		public String getPrefix(String uri) {
			return null;
		}
	};

	/**
	 * Performs an xpath match on the given source document and prepares a map
	 * of the field name->list of values for this field.
	 * 
	 * @param source
	 *            document from which the fields will be extracted.
	 * @param fields
	 *            map of field name->xpath for that field to search for in the
	 *            given doc.
	 */
	public static Map<String, List<String>> extractFields(Document source,
			Map<String, String> fields) {
		Map<String, List<String>> extractedFields = new HashMap<String, List<String>>();

		Iterator<Entry<String, String>> iterator = fields.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, String> entry = iterator.next();
			List<String> values = new ArrayList<String>();
			XPath xPath = XPathFactory.newInstance().newXPath();
			xPath.setNamespaceContext(ctx);

			try {
				NodeList matchingNodes = (NodeList) xPath.evaluate(entry
						.getValue(), source, XPathConstants.NODESET);
				for (int i = 0; i < matchingNodes.getLength(); i++) {
					// TODO: what about attributes?
					values.add(matchingNodes.item(i).getTextContent());
				}
				extractedFields.put(entry.getKey(), values);
			} catch (XPathExpressionException e) {
				throw new RuntimeException(e);
			}
		}
		return extractedFields;
	}

	/**
	 * Returns the value of the first matching node given the xpath and the
	 * source doc.
	 * 
	 * @param source
	 * @param fieldPath
	 * @return
	 */
	public static String getValue(Document source, String fieldPath) {
		XPath xPath = XPathFactory.newInstance().newXPath();
		xPath.setNamespaceContext(ctx);
		Node matchingNode;
		try {
			matchingNode = (Node) xPath.evaluate(fieldPath, source,
					XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			throw new RuntimeException(e);
		}

		return (matchingNode != null) ? matchingNode.getTextContent() : "";
	}

	public static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException{
		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
		documentBuilderFactory.setNamespaceAware(true);
		return documentBuilderFactory.newDocumentBuilder();
		
	}
}
