/***************************************************************************
    Copyright          : (C) 2002 by Neoworks Limited. All rights reserved
    URL                : http://www.neoworks.com
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

package com.neoworks.util;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.apache.xerces.dom.DocumentImpl;
import org.apache.log4j.Category;
import org.apache.xpath.XPathAPI;
import javax.xml.transform.TransformerException;
import java.lang.Object;
import java.lang.String;
import java.lang.Class;
import java.lang.Throwable;
import java.lang.Exception;
import org.w3c.dom.Element;
import java.lang.Error;
import java.lang.RuntimeException;
import java.lang.ClassNotFoundException;
import java.lang.NoClassDefFoundError;
import java.lang.LinkageError;
import java.lang.StringBuffer;

/**
 * This class wraps up DOM XPath queries so they're a bit easier to do.
 *
 * <p>The more observant amongst you may have noticed that this is a wrapper for
 * a wrapper class.  This is deliberate as XPathAPI is intended as a stopgap until
 * the methods are rationalised and included in the Xalan API.  This could mean an API
 * change, meaning a second level of wrappers is required to ensure future compatibility
 * with Xalan.</p>
 *
 * @author Nick Vincent <a href="mailto:nick@neoworks.com">nick@neoworks.com</a>
 * @version $Revision: 1.2 $
 */
public class XPathQuery
{
	private static final Category log = Category.getInstance(XPathQuery.class.getName());
	private static final boolean logDebugEnabled = log.isDebugEnabled();
	private static final boolean logInfoEnabled = log.isInfoEnabled();

	/**
	 * Private Constructor
	 */
	private XPathQuery()
	{
	}
	
	/**
	 * Perform the given XPath query in the given document, returning a list
	 * of matching nodes.
	 *
	 * @return A list of nodes matching the XPath query
	 * @param node The node to query on
	 * @param xpath the XPath query to run
	 */
	public static NodeList getNodes(Node node, String xpath)
	{
		NodeList nl = null;
		try
		{
			nl = XPathAPI.selectNodeList( node, xpath );
		}
		catch ( TransformerException te )
		{
			log.warn("XPath query " + xpath + " threw exception.",te);
		}
		
		return nl;
		/*
		NodeList nl = null;
		try
		{
			nl = XPathAPI.selectNodeList(node, xpath);		// Use the simple XPath API to select a node.
		}
		catch (Exception e2)
		{
			log.warn("selectNodeList threw: " + e2.toString() + " perhaps your xpath didn't select any nodes",e2);
		}
		
		// Return an empty list if we've generated a null somehow.
		// Whether a dummy element is the right thing to use is questionable, 
		// but I couldn't see anything better implementing NodeList to use.
		if (nl == null) nl = (NodeList) new DocumentImpl().createElement("dummy");
		
		// If logging is turned on dump the XPath doc to the console
		if (logDebugEnabled)
		{
			log.debug("XPath running query "+xpath+" on XML \n" + DOMUtils.DOM2String(node, true));
			log.debug("Produced "+nl.getLength()+" result nodes");
		}
		
		return nl;
		 */
	}
	
	/**
	 * Perform the given XPath query on the given document, returning a list
	 * of matching nodes
	 *
	 * @return A list of nodes matching the XPath query
	 * @param doc The document to query on
	 * @param xpath the XPath query to run
	 */
	public static NodeList getNodes(Document doc, String xpath)
	{
		Node root = doc.getDocumentElement();		// Get the root element from the Document as this is what XPathAPI needs
		return getNodes(root, xpath);		
	}
	
	/**
	 * Perform the given XPath query on the given DOM node, returning a
	 * single matching node.
	 *
	 * @return The first matching node, otherwise null
	 * @param node The node to query on
	 * @param xpath the XPath query to run
	 */
	public static Node getSingleNode(Node node, String xpath)
	{
		NodeList nl = getNodes(node, xpath);
		
		if (nl.getLength() == 0)
		{
			return null;
		}
		return nl.item(0);
	}
	
	/**
	 * Perform the given XPath query on the given document, returning a
	 * single matching node.
	 *
	 * @return A matching node, otherwise null
	 * @param doc The document to query on
	 * @param xpath the XPath query to run
	 */
	public static Node getSingleNode(Document doc,String xpath)
	{
		Node root = doc.getDocumentElement();		// Get the root element from the Document as this is what XPathAPI needs
		return getSingleNode(root, xpath);		
	}
}

