package eu.dnetlib.functionality.lightui.formatter;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.sun.org.apache.xpath.internal.XPathAPI;

public class EFGRottenXMLUtil {
	private static final TransformerFactory tFactory = TransformerFactory.newInstance();
	private static final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		
	private static final Log log = LogFactory.getLog(EFGRottenXMLUtil.class); // NOPMD by marko on 11/24/08 5:02 PM

	public static String verify(Object o, NodeList errors) {
		try {
			if (o instanceof Node) return verifyNode((Node) o, calculateErrors(errors));
			if (o instanceof NodeList) return verifyNodeList((NodeList) o, calculateErrors(errors));
		} catch (Exception e) {
			log.error(e);
		}
		return o.toString();
	}

	private static String verifyNodeList(NodeList nl, List<Map<String, String>> errors) throws Exception {
		for (int i=0; i<nl.getLength(); i++) {
			String res = verifyNode(nl.item(i), errors) ;
			if (res.length() > 0) return res;
		}
		return "";
	}

	private static String verifyNode(Node node, List<Map<String, String>> errors) throws Exception {
		String value = node.getNodeValue();
		if (value == null) return "";
		value = value.trim();
		if (value.isEmpty()) return "";
		for (Map<String, String> error : errors) {
			if (value.equals(error.get("term")))
				if (verifyXpath(node, error.get("xpath")))
					return error.get("vocabularies");
		}
		return "";
	}



	private static boolean verifyXpath(Node node, String xpath) throws Exception {
		NodeList nl = XPathAPI.selectNodeList(cloneDoc(node.getOwnerDocument()), xpath);
		String path = nodeGetPath(node);

		for (int i=0; i<nl.getLength(); i++) {
			String newPath = nodeGetPath(nl.item(i));
			if (path.equals(newPath))
				return true;
		}
		return false;

	}

	private static String nodeGetPath(Node node) {
		if (node != null) {
			String name = node.getNodeName();
			if (name.contains("efgEntity"))
				return "/START";
			else if (name.isEmpty()) 
				return nodeGetPath(node.getParentNode());
			else
				return nodeGetPath(node.getParentNode()) + "/" + name;
		}
		return "/START";
	}	


	private static List<Map<String, String>> calculateErrors(NodeList nl) {
		List<Map<String, String>> res = new ArrayList<Map<String, String>>();

		for (int i=0; i < nl.getLength(); i++) {
			NamedNodeMap attrs = nl.item(i).getAttributes();
			Map<String, String> error = new HashMap<String, String>();
			error.put("term", attrs.getNamedItem("term").getNodeValue());
			error.put("xpath", attrs.getNamedItem("xpath").getNodeValue());
			error.put("vocabularies", attrs.getNamedItem("vocabularies").getNodeValue());
			res.add(error);
		}
		return res;
	}


	public static Document cloneDoc(Document doc) throws Exception {
		Source source = new DOMSource(doc);
		StringWriter xml = new StringWriter();
		StreamResult result = new StreamResult(xml);
		tFactory.newTransformer().transform(source, result);
		return docFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml.toString())));
	}

}
