/*
	Copyright (c) 2009-2011 Olivier Chafik, All Rights Reserved
	
	This file is part of JNAerator (http://jnaerator.googlecode.com/).
	
	JNAerator is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	JNAerator is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.ochafik.xml;

import java.lang.ref.SoftReference;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.ochafik.lang.SyntaxUtils;

public class XPathUtils {
	public static Map<String, SoftReference<XPathExpression>> xPathExpressionsCache = new LinkedHashMap<String, SoftReference<XPathExpression>>();
	private static SoftReference<XPath> sharedXPath; 
	public static XPath getSharedXPath() {
		XPath xPath = null;
		if (sharedXPath != null)
			xPath = sharedXPath.get();
		if (xPath == null) {
			XPathFactory xPathFactory = XPathFactory.newInstance();
			sharedXPath = new SoftReference<XPath>(xPath = xPathFactory.newXPath()); 
		}
		return xPath;
	}
	public static List<Node> findNodesByXPath(String xPathString, Object source) throws XPathExpressionException {
		return XMLUtils.list((NodeList)getXPathExpression(xPathString).evaluate(source, XPathConstants.NODESET));
	}
	public static Iterable<Node> findNodesIterableByXPath(String xPathString, Object source) throws XPathExpressionException {
		return SyntaxUtils.iterable((NodeList)getXPathExpression(xPathString).evaluate(source, XPathConstants.NODESET));
	}
	public static Node findNodeByXPath(String xPathString, Object source) throws XPathExpressionException {
		NodeList list = (NodeList)getXPathExpression(xPathString).evaluate(source, XPathConstants.NODESET);
		int len = list.getLength();
		return len == 0 ? null : list.item(0); 
	}
	public static String findStringByXPath(String xPathString, Object source) throws XPathExpressionException {
		return (String)getXPathExpression(xPathString).evaluate(source, XPathConstants.STRING);
	}
	public static XPathExpression getXPathExpression(String xPathString) throws XPathExpressionException {
		SoftReference<XPathExpression> ref = xPathExpressionsCache.get(xPathString);
		XPathExpression expression = ref == null ? null : ref.get();
		if (expression == null)
			xPathExpressionsCache.put(xPathString, new SoftReference<XPathExpression>(expression = getSharedXPath().compile(xPathString)));
				
		return expression;
	}

}
