content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE 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.
   *
   *  AndroidIDE 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 AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id: NodeTest.java,v 1.2.4.2 2005/09/15 00:21:14 jeffsuttor Exp $
   */
  package jaxp.sun.org.apache.xpath.internal.patterns;
  
  import jaxp.sun.org.apache.xml.internal.dtm.DTM;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMFilter;
  import jaxp.sun.org.apache.xpath.internal.Expression;
  import jaxp.sun.org.apache.xpath.internal.ExpressionOwner;
  import jaxp.sun.org.apache.xpath.internal.XPath;
  import jaxp.sun.org.apache.xpath.internal.XPathContext;
  import jaxp.sun.org.apache.xpath.internal.XPathVisitable;
  import jaxp.sun.org.apache.xpath.internal.XPathVisitor;
  import jaxp.sun.org.apache.xpath.internal.objects.XNumber;
  import jaxp.sun.org.apache.xpath.internal.objects.XObject;
  import jaxp.xml.transform.TransformerException;
  
  /**
   * This is the basic node test class for both match patterns and location path
   * steps.
   * @xsl.usage advanced
   */
  public class NodeTest extends Expression
  {
      static final long serialVersionUID = -5736721866747906182L;
  
    /**
     * The namespace or local name for node tests with a wildcard.
     *  @see <a href="http://www.w3.org/TR/xpath#NT-NameTest">the XPath NameTest production.</a>
     */
    public static final String WILD = "*";
  
    /**
     * The URL to pass to the Node#supports method, to see if the
     * DOM has already been stripped of whitespace nodes.
     */
    public static final String SUPPORTS_PRE_STRIPPING =
      "http://xml.apache.org/xpath/features/whitespace-pre-stripping";
  
    /**
     * This attribute determines which node types are accepted.
     * @serial
     */
    protected int m_whatToShow;
  
    /**
     * Special bitmap for match patterns starting with a function.
     * Make sure this does not conflict with {@link org.w3c.dom.traversal.NodeFilter}.
     */
    public static final int SHOW_BYFUNCTION = 0x00010000;
  
    /**
     * This attribute determines which node types are accepted.
     * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter}
     * interface.
     *
     * @return bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}.
     */
    public int getWhatToShow()
    {
      return m_whatToShow;
    }
  
    /**
     * This attribute determines which node types are accepted.
     * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter}
     * interface.
     *
     * @param what bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}.
     */
    public void setWhatToShow(int what)
    {
      m_whatToShow = what;
    }
  
    /**
     * The namespace to be tested for, which may be null.
     *  @serial
     */
    String m_namespace;
  
    /**
     * Return the namespace to be tested.
     *
     * @return The namespace to be tested for, or {@link #WILD}, or null.
     */
    public String getNamespace()
    {
      return m_namespace;
    }
  
    /**
     * Set the namespace to be tested.
     *
     * @param ns The namespace to be tested for, or {@link #WILD}, or null.
     */
    public void setNamespace(String ns)
    {
      m_namespace = ns;
    }
  
    /**
     * The local name to be tested for.
     *  @serial
     */
    protected String m_name;
  
    /**
     * Return the local name to be tested.
     *
     * @return the local name to be tested, or {@link #WILD}, or an empty string.
     */
    public String getLocalName()
    {
      return (null == m_name) ? "" : m_name;
    }
  
    /**
     * Set the local name to be tested.
     *
     * @param name the local name to be tested, or {@link #WILD}, or an empty string.
     */
    public void setLocalName(String name)
    {
      m_name = name;
    }
  
    /**
     * Statically calculated score for this test.  One of
     *  {@link #SCORE_NODETEST},
     *  {@link #SCORE_NONE},
     *  {@link #SCORE_NSWILD},
     *  {@link #SCORE_QNAME}, or
     *  {@link #SCORE_OTHER}.
     *  @serial
     */
    XNumber m_score;
  
    /**
     * The match score if the pattern consists of just a NodeTest.
     *  @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
     */
    public static final XNumber SCORE_NODETEST =
      new XNumber(XPath.MATCH_SCORE_NODETEST);
  
    /**
     * The match score if the pattern pattern has the form NCName:*.
     *  @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
     */
    public static final XNumber SCORE_NSWILD =
      new XNumber(XPath.MATCH_SCORE_NSWILD);
  
    /**
     * The match score if the pattern has the form
     * of a QName optionally preceded by an @ character.
     *  @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
     */
    public static final XNumber SCORE_QNAME =
      new XNumber(XPath.MATCH_SCORE_QNAME);
  
    /**
     * The match score if the pattern consists of something
     * other than just a NodeTest or just a qname.
     *  @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
     */
    public static final XNumber SCORE_OTHER =
      new XNumber(XPath.MATCH_SCORE_OTHER);
  
    /**
     * The match score if no match is made.
     *  @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
     */
    public static final XNumber SCORE_NONE =
      new XNumber(XPath.MATCH_SCORE_NONE);
  
    /**
     * Construct an NodeTest that tests for namespaces and node names.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     * @param namespace The namespace to be tested.
     * @param name The local name to be tested.
     */
    public NodeTest(int whatToShow, String namespace, String name)
    {
      initNodeTest(whatToShow, namespace, name);
    }
  
    /**
     * Construct an NodeTest that doesn't test for node names.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     */
    public NodeTest(int whatToShow)
    {
      initNodeTest(whatToShow);
    }
  
    /**
     * @see Expression#deepEquals(Expression)
     */
    public boolean deepEquals(Expression expr)
    {
          if(!isSameClass(expr))
                  return false;
  
          NodeTest nt = (NodeTest)expr;
  
          if(null != nt.m_name)
          {
                  if(null == m_name)
                          return false;
                  else if(!nt.m_name.equals(m_name))
                          return false;
          }
          else if(null != m_name)
                  return false;
  
          if(null != nt.m_namespace)
          {
                  if(null == m_namespace)
                          return false;
                  else if(!nt.m_namespace.equals(m_namespace))
                          return false;
          }
          else if(null != m_namespace)
                  return false;
  
          if(m_whatToShow != nt.m_whatToShow)
                  return false;
  
          if(m_isTotallyWild != nt.m_isTotallyWild)
                  return false;
  
          return true;
    }
  
    /**
     * Null argument constructor.
     */
    public NodeTest(){}
  
    /**
     * Initialize this node test by setting the whatToShow property, and
     * calculating the score that this test will return if a test succeeds.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     */
    public void initNodeTest(int whatToShow)
    {
  
      m_whatToShow = whatToShow;
  
      calcScore();
    }
  
    /**
     * Initialize this node test by setting the whatToShow property and the
     * namespace and local name, and
     * calculating the score that this test will return if a test succeeds.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     * @param namespace The namespace to be tested.
     * @param name The local name to be tested.
     */
    public void initNodeTest(int whatToShow, String namespace, String name)
    {
  
      m_whatToShow = whatToShow;
      m_namespace = namespace;
      m_name = name;
  
      calcScore();
    }
  
    /**
     * True if this test has a null namespace and a local name of {@link #WILD}.
     *  @serial
     */
    private boolean m_isTotallyWild;
  
    /**
     * Get the static score for this node test.
     * @return Should be one of the SCORE_XXX constants.
     */
    public XNumber getStaticScore()
    {
      return m_score;
    }
  
    /**
     * Set the static score for this node test.
     * @param score Should be one of the SCORE_XXX constants.
     */
    public void setStaticScore(XNumber score)
    {
      m_score = score;
    }
  
    /**
     * Static calc of match score.
     */
    protected void calcScore()
    {
  
      if ((m_namespace == null) && (m_name == null))
        m_score = SCORE_NODETEST;
      else if (((m_namespace == WILD) || (m_namespace == null))
               && (m_name == WILD))
        m_score = SCORE_NODETEST;
      else if ((m_namespace != WILD) && (m_name == WILD))
        m_score = SCORE_NSWILD;
      else
        m_score = SCORE_QNAME;
  
      m_isTotallyWild = (m_namespace == null && m_name == WILD);
    }
  
    /**
     * Get the score that this test will return if a test succeeds.
     *
     *
     * @return the score that this test will return if a test succeeds.
     */
    public double getDefaultScore()
    {
      return m_score.num();
    }
  
    /**
     * Tell what node type to test, if not DTMFilter.SHOW_ALL.
     *
     * @param whatToShow Bit set defined mainly by
     *        {@link DTMFilter}.
     * @return the node type for the whatToShow.  Since whatToShow can specify
     *         multiple types, it will return the first bit tested that is on,
     *         so the caller of this function should take care that this is
     *         the function they really want to call.  If none of the known bits
     *         are set, this function will return zero.
     */
    public static int getNodeTypeTest(int whatToShow)
    {
      // %REVIEW% Is there a better way?
      if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT))
        return DTM.ELEMENT_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE))
        return DTM.ATTRIBUTE_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_TEXT))
        return DTM.TEXT_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT))
        return DTM.DOCUMENT_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT))
        return DTM.DOCUMENT_FRAGMENT_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE))
        return DTM.NAMESPACE_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_COMMENT))
        return DTM.COMMENT_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION))
        return DTM.PROCESSING_INSTRUCTION_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE))
        return DTM.DOCUMENT_TYPE_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_ENTITY))
        return DTM.ENTITY_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE))
        return DTM.ENTITY_REFERENCE_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_NOTATION))
        return DTM.NOTATION_NODE;
  
      if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION))
        return DTM.CDATA_SECTION_NODE;
  
  
      return 0;
    }
  
  
    /**
     * Do a diagnostics dump of a whatToShow bit set.
     *
     *
     * @param whatToShow Bit set defined mainly by
     *        {@link DTMFilter}.
     */
    public static void debugWhatToShow(int whatToShow)
    {
  
      java.util.Vector v = new java.util.Vector();
  
      if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE))
        v.addElement("SHOW_ATTRIBUTE");
  
      if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE))
        v.addElement("SHOW_NAMESPACE");
  
      if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION))
        v.addElement("SHOW_CDATA_SECTION");
  
      if (0 != (whatToShow & DTMFilter.SHOW_COMMENT))
        v.addElement("SHOW_COMMENT");
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT))
        v.addElement("SHOW_DOCUMENT");
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT))
        v.addElement("SHOW_DOCUMENT_FRAGMENT");
  
      if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE))
        v.addElement("SHOW_DOCUMENT_TYPE");
  
      if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT))
        v.addElement("SHOW_ELEMENT");
  
      if (0 != (whatToShow & DTMFilter.SHOW_ENTITY))
        v.addElement("SHOW_ENTITY");
  
      if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE))
        v.addElement("SHOW_ENTITY_REFERENCE");
  
      if (0 != (whatToShow & DTMFilter.SHOW_NOTATION))
        v.addElement("SHOW_NOTATION");
  
      if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION))
        v.addElement("SHOW_PROCESSING_INSTRUCTION");
  
      if (0 != (whatToShow & DTMFilter.SHOW_TEXT))
        v.addElement("SHOW_TEXT");
  
      int n = v.size();
  
      for (int i = 0; i < n; i++)
      {
        if (i > 0)
          System.out.print(" | ");
  
        System.out.print(v.elementAt(i));
      }
  
      if (0 == n)
        System.out.print("empty whatToShow: " + whatToShow);
  
      System.out.println();
    }
  
    /**
     * Two names are equal if they and either both are null or
     * the name t is wild and the name p is non-null, or the two
     * strings are equal.
     *
     * @param p part string from the node.
     * @param t target string, which may be {@link #WILD}.
     *
     * @return true if the strings match according to the rules of this method.
     */
    private static final boolean subPartMatch(String p, String t)
    {
  
      // boolean b = (p == t) || ((null != p) && ((t == WILD) || p.equals(t)));
      // System.out.println("subPartMatch - p: "+p+", t: "+t+", result: "+b);
      return (p == t) || ((null != p) && ((t == WILD) || p.equals(t)));
    }
  
    /**
     * This is temporary to patch over Xerces issue with representing DOM
     * namespaces as "".
     *
     * @param p part string from the node, which may represent the null namespace
     *        as null or as "".
     * @param t target string, which may be {@link #WILD}.
     *
     * @return true if the strings match according to the rules of this method.
     */
    private static final boolean subPartMatchNS(String p, String t)
    {
  
      return (p == t)
             || ((null != p)
                 && ((p.length() > 0)
                     ? ((t == WILD) || p.equals(t)) : null == t));
    }
  
    /**
     * Tell what the test score is for the given node.
     *
     *
     * @param xctxt XPath runtime context.
     * @param context The node being tested.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public XObject execute(XPathContext xctxt, int context)
            throws TransformerException
    {
  
      DTM dtm = xctxt.getDTM(context);
      short nodeType = dtm.getNodeType(context);
  
      if (m_whatToShow == DTMFilter.SHOW_ALL)
        return m_score;
  
      int nodeBit = (m_whatToShow & (0x00000001 << (nodeType - 1)));
  
      switch (nodeBit)
      {
      case DTMFilter.SHOW_DOCUMENT_FRAGMENT :
      case DTMFilter.SHOW_DOCUMENT :
        return SCORE_OTHER;
      case DTMFilter.SHOW_COMMENT :
        return m_score;
      case DTMFilter.SHOW_CDATA_SECTION :
      case DTMFilter.SHOW_TEXT :
  
        // was:
        // return (!xctxt.getDOMHelper().shouldStripSourceNode(context))
        //       ? m_score : SCORE_NONE;
        return m_score;
      case DTMFilter.SHOW_PROCESSING_INSTRUCTION :
        return subPartMatch(dtm.getNodeName(context), m_name)
               ? m_score : SCORE_NONE;
  
      // From the draft: "Two expanded names are equal if they
      // have the same local part, and either both have no URI or
      // both have the same URI."
      // "A node test * is true for any node of the principal node type.
      // For example, child::* will select all element children of the
      // context node, and attribute::* will select all attributes of
      // the context node."
      // "A node test can have the form NCName:*. In this case, the prefix
      // is expanded in the same way as with a QName using the context
      // namespace declarations. The node test will be true for any node
      // of the principal type whose expanded name has the URI to which
      // the prefix expands, regardless of the local part of the name."
      case DTMFilter.SHOW_NAMESPACE :
      {
        String ns = dtm.getLocalName(context);
  
        return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE;
      }
      case DTMFilter.SHOW_ATTRIBUTE :
      case DTMFilter.SHOW_ELEMENT :
      {
        return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name)))
               ? m_score : SCORE_NONE;
      }
      default :
        return SCORE_NONE;
      }  // end switch(testType)
    }
  
    /**
     * Tell what the test score is for the given node.
     *
     *
     * @param xctxt XPath runtime context.
     * @param context The node being tested.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public XObject execute(XPathContext xctxt, int context,
                           DTM dtm, int expType)
            throws TransformerException
    {
  
      if (m_whatToShow == DTMFilter.SHOW_ALL)
        return m_score;
  
      int nodeBit = (m_whatToShow & (0x00000001
                     << ((dtm.getNodeType(context)) - 1)));
  
      switch (nodeBit)
      {
      case DTMFilter.SHOW_DOCUMENT_FRAGMENT :
      case DTMFilter.SHOW_DOCUMENT :
        return SCORE_OTHER;
      case DTMFilter.SHOW_COMMENT :
        return m_score;
      case DTMFilter.SHOW_CDATA_SECTION :
      case DTMFilter.SHOW_TEXT :
  
        // was:
        // return (!xctxt.getDOMHelper().shouldStripSourceNode(context))
        //       ? m_score : SCORE_NONE;
        return m_score;
      case DTMFilter.SHOW_PROCESSING_INSTRUCTION :
        return subPartMatch(dtm.getNodeName(context), m_name)
               ? m_score : SCORE_NONE;
  
      // From the draft: "Two expanded names are equal if they
      // have the same local part, and either both have no URI or
      // both have the same URI."
      // "A node test * is true for any node of the principal node type.
      // For example, child::* will select all element children of the
      // context node, and attribute::* will select all attributes of
      // the context node."
      // "A node test can have the form NCName:*. In this case, the prefix
      // is expanded in the same way as with a QName using the context
      // namespace declarations. The node test will be true for any node
      // of the principal type whose expanded name has the URI to which
      // the prefix expands, regardless of the local part of the name."
      case DTMFilter.SHOW_NAMESPACE :
      {
        String ns = dtm.getLocalName(context);
  
        return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE;
      }
      case DTMFilter.SHOW_ATTRIBUTE :
      case DTMFilter.SHOW_ELEMENT :
      {
        return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name)))
               ? m_score : SCORE_NONE;
      }
      default :
        return SCORE_NONE;
      }  // end switch(testType)
    }
  
    /**
     * Test the current node to see if it matches the given node test.
     *
     * @param xctxt XPath runtime context.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public XObject execute(XPathContext xctxt)
            throws TransformerException
    {
      return execute(xctxt, xctxt.getCurrentNode());
    }
  
    /**
     * Node tests by themselves do not need to fix up variables.
     */
    public void fixupVariables(java.util.Vector vars, int globalsSize)
    {
      // no-op
    }
  
    /**
     * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
     */
    public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
    {
          assertion(false, "callVisitors should not be called for this object!!!");
    }
  
  }
  