/*
 * Created on 02.12.2003
 *
 * (c) Stabsstelle IKT-Strategie des Bundes
 */
package at.gv.egovernment.moa.spss.slinterface;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) 
 */
public class XPathUtils 
{
  /**
   * The XPath context for the XPath engine.
   */
  protected XPathContext xPathContext_;
  /**
   * The prefix resolver for the XPath engine.
   */
  protected PrefixResolver prefixResolver_;
  /**
   * The XPath engine.
   */
  protected XPath xPath_;
  /* ==================================================================================================== */
  public void setupContext(String xPathExpr, Node namespaceNode, String additionalNSPrefixes)
    throws Exception
  {
    try
    {
      // Set up a new evaluation context
      xPathContext_ = new XPathContext();
      // Set up the namespace prefix resolver for the XPath engine
      prefixResolver_ = new PrefixResolver(namespaceNode, additionalNSPrefixes);
      // Initialize XPath engine
      xPath_ = new XPath(xPathExpr, null, prefixResolver_, XPath.SELECT, null);
    }
    catch (Exception e)
    {
      throw new Exception("Setting up XPath evaluation context failed.", e);
    }
  }
  /* ---------------------------------------------------------------------------------------------------- */
  public NodeList selectNodeSet(Node contextNode) throws Exception
  {
    XObject xObject;
    try
    {
      xObject = xPath_.execute(xPathContext_, contextNode, prefixResolver_);
      return xObject.nodelist();
    }
    catch (Exception e)
    {
      throw new Exception("Executing XPath expression failed.", e);
    }
  }
  /* ---------------------------------------------------------------------------------------------------- */
  public boolean selectBoolean(Node contextNode) throws Exception
  {
    XObject xObject;
    try
    {
      xObject = xPath_.execute(xPathContext_, contextNode, prefixResolver_);
      return xObject.bool();
    }
    catch (Exception e)
    {
      throw new Exception("Executing XPath expression failed.", e);
    }
  }
  /* ==================================================================================================== */
  /**
   * Special extension of the {@link org.apache.xml.utils.PrefixResolverDefault} interface. Used to
   * configure the Apache Xalan XPath engine which is employed as the backbone of this class.
   */
  protected class PrefixResolver extends PrefixResolverDefault
  {
    /**
     * Contains the additionally specified namespace prefix (key) to namespace URI (value) attributions.
     */
    protected HashMap additionalNSPrefixesMap_;
    /* ================================================================================================== */
    /**
     * Basic constructor.
     *
     * @param xpathExpressionContext The namespace declarations in scope for this node will be used to get
     *                               the namespace uri for a prefix specified in the XPath expression.
     *
     * @param additionalNSPrefixes Allows the specification of additional prefix to uri attributions apart
     *                             from the declarations in scope for the parameter 
     *                             xpathExpressionContext. May be null.
     */
    public PrefixResolver(Node xpathExpressionContext, String additionalNSPrefixes) throws Exception
    {
      super(xpathExpressionContext);
      additionalNSPrefixesMap_ = new HashMap();
      // Register the specified additional namespace prefix to namespace uri attributions
      if (additionalNSPrefixes != null)
      {
        StringTokenizer tokenizer = new StringTokenizer(additionalNSPrefixes, " ");
        while (tokenizer.hasMoreTokens())
        {
          String prefix = tokenizer.nextToken();
          if (!tokenizer.hasMoreTokens())
          {
            // There must be an even number of tokens in the string
            throw new Exception("Parameter \"additionalNSPrefixes\" must have an even number of tokens.");
          }
          String uri = tokenizer.nextToken();
          additionalNSPrefixesMap_.put(prefix, uri);
        }
      }
    }
    /* -------------------------------------------------------------------------------------------------- */
    /**
     * Gets the namespace uri for the specified namespace prefix. The additionally specified prefixes
     * overrule the prefixes found in the specified namespace node.
     *
     * @param prefix The namespace prefix for which a namespace uri should be found.
     *
     * @return the namespace uri for the specified namespace prefix.
     */
    public String getNamespaceForPrefix(String prefix)
    {
      String additionalURI = (String) additionalNSPrefixesMap_.get(prefix);
      return (additionalURI != null)
             ? additionalURI
             : super.getNamespaceForPrefix(prefix);
    }
  }
}