/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, Lotus
 * Development Corporation., http://www.lotus.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.xpath.axes;

import org.apache.xpath.compiler.OpCodes;
import org.apache.xpath.compiler.Compiler;
import org.apache.xpath.patterns.NodeTest;

import org.w3c.dom.traversal.NodeFilter;

/**
 * This class is both a factory for XPath location path expressions, 
 * which are built from the opcode map output, and an analysis engine 
 * for the location path expressions in order to provide optimization hints.
 */
public class WalkerFactory
{

  /**
   * <meta name="usage" content="advanced"/>
   * This method is for building an array of possible levels
   * where the target element(s) could be found for a match.
   * @param xpath The xpath that is executing.
   * @param context The current source tree context node.
   *
   * @param lpi The owning location path iterator.
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param stepOpCodePos The opcode position for the step.
   *
   * @return non-null AxesWalker derivative.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static AxesWalker loadOneWalker(
          LocPathIterator lpi, Compiler compiler, int stepOpCodePos)
            throws javax.xml.transform.TransformerException
  {

    AxesWalker firstWalker = null;
    int stepType = compiler.getOpMap()[stepOpCodePos];

    if (stepType != OpCodes.ENDOP)
    {

      // m_axesWalkers = new AxesWalker[1];
      // As we unwind from the recursion, create the iterators.
      firstWalker = createDefaultWalker(compiler, stepType, lpi, 0);

      firstWalker.init(compiler, stepOpCodePos, stepType);
    }

    return firstWalker;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * This method is for building an array of possible levels
   * where the target element(s) could be found for a match.
   * @param xpath The xpath that is executing.
   * @param context The current source tree context node.
   *
   * @param lpi The owning location path iterator object.
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param stepOpCodePos The opcode position for the step.
   * @param stepIndex The top-level step index withing the iterator.
   *
   * @return non-null AxesWalker derivative.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static AxesWalker loadWalkers(
          LocPathIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex)
            throws javax.xml.transform.TransformerException
  {

    int stepType;
    AxesWalker firstWalker = null;
    AxesWalker walker, prevWalker = null;
    int ops[] = compiler.getOpMap();
    int analysis = analyze(compiler, stepOpCodePos, stepIndex);

    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
    {
      walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);

      walker.init(compiler, stepOpCodePos, stepType);
      // walker.setAnalysis(analysis);

      if (null == firstWalker)
      {
        firstWalker = walker;
      }
      else
      {
        prevWalker.setNextWalker(walker);
        walker.setPrevWalker(prevWalker);
      }

      prevWalker = walker;
      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);

      if (stepOpCodePos < 0)
        break;
    }

    return firstWalker;
  }

  /**
   * Create a new LocPathIterator iterator.  The exact type of iterator 
   * returned is based on an analysis of the XPath operations.
   *
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param opPos The position of the operation code for this itterator.
   *
   * @return non-null reference to a LocPathIterator or derivative.
   *
   * @throws javax.xml.transform.TransformerException
   */
  public static LocPathIterator newLocPathIterator(
          Compiler compiler, int opPos)
            throws javax.xml.transform.TransformerException
  {
    int firstStepPos = compiler.getFirstChildPos(opPos);
    int analysis = analyze(compiler, firstStepPos, 0);
    
    
    // Is the iteration exactly one child step?
    if ((BIT_CHILD | 0x00000001) == (analysis & (BIT_CHILD | BITS_COUNT)))
    {
      //                 BIT_NODETEST_ANY: 1000000000000000000000000000000
      //                 BIT_PREDICATE:                      1000000000000
      // new iterator:  ChildIterator: 1000000000000010000000000000001, node()
      // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
      if ((BIT_NODETEST_ANY == (analysis & BIT_NODETEST_ANY)) && 
         !(BIT_PREDICATE == (analysis & BIT_PREDICATE)))
      {
        if (DEBUG_ITERATOR_CREATION)
          System.out.println("new iterator:  ChildIterator: " 
                            + Integer.toBinaryString(analysis) + ", "
                             + compiler.toString());

        // Use simple child iteration without any test.
        return new ChildIterator(compiler, opPos, analysis);
      }
      else
      {
        if (DEBUG_ITERATOR_CREATION)
          System.out.println("new iterator:  ChildTestIterator: " 
                            + Integer.toBinaryString(analysis) + ", "
                             + compiler.toString());

        // Else use simple node test iteration with predicate test.
        return new ChildTestIterator(compiler, opPos, analysis);
      }
    }
    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
    else if ((BIT_ATTRIBUTE | 0x00000001)
             == (analysis & (BIT_ATTRIBUTE | BITS_COUNT)))
    {
      if (DEBUG_ITERATOR_CREATION)
        System.out.println("new iterator:  AttributeIterator: " 
                          + Integer.toBinaryString(analysis) + ", "
                           + compiler.toString());

      // Then use a simple iteration of the attributes, with node test 
      // and predicate testing.
      return new AttributeIterator(compiler, opPos, analysis);
    }
    // Analysis of "//center":
    // bits: 1001000000001010000000000000011
    // count: 3
    // root
    // child:node()
    // BIT_DESCENDANT_OR_SELF
    // It's highly possible that we should have a seperate bit set for 
    // "//foo" patterns.
    // For at least the time being, we can't optimize patterns like 
    // "//table[3]", because this has to be analyzed as 
    // "/descendant-or-self::node()/table[3]" in order for the indexes 
    // to work right.
    else if (0 == (BIT_PREDICATE & analysis) &&
            (((BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | 0x00000001)
             == (analysis
                 & (BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BITS_COUNT))) ||
            ((BIT_DESCENDANT_OR_SELF | BIT_SELF | 0x00000002)
             == (analysis
                 & (BIT_DESCENDANT_OR_SELF | BIT_SELF | BITS_COUNT))) 
            
            /* ".//center" -- 1000010000001010000000000000011 */     
            || ((BIT_DESCENDANT_OR_SELF | BIT_SELF | BIT_CHILD | BIT_NODETEST_ANY | 0x00000003)
             == (analysis
              & (BIT_DESCENDANT_OR_SELF | BIT_SELF | BIT_CHILD | BIT_NODETEST_ANY | BITS_COUNT)))

            /* "//center" -- 1001000000001010000000000000011 */
            || ((BIT_DESCENDANT_OR_SELF | BIT_ROOT | BIT_CHILD | BIT_NODETEST_ANY | 
              BIT_ANY_DESCENDANT_FROM_ROOT | 0x00000003)
             == (analysis
                 & (BIT_DESCENDANT_OR_SELF | BIT_ROOT | BIT_CHILD | 
                    BIT_NODETEST_ANY | BIT_ANY_DESCENDANT_FROM_ROOT | BITS_COUNT))))
    )
    {
      if (DEBUG_ITERATOR_CREATION)
        System.out.println("new iterator:  DescendantIterator: " 
                          + Integer.toBinaryString(analysis) + ", "
                           + compiler.toString());

      return new DescendantIterator(compiler, opPos, analysis);
    }
    else
    {
      if (DEBUG_ITERATOR_CREATION)
        System.out.println("new iterator:  LocPathIterator: " 
                          + Integer.toBinaryString(analysis) + ", "
                           + compiler.toString());
      return new LocPathIterator(compiler, opPos, analysis, true);
    }
  }

  /**
   * Analyze the location path and return 32 bits that give information about 
   * the location path as a whole.  See the BIT_XXX constants for meaning about 
   * each of the bits.
   *
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param stepOpCodePos The opcode position for the step.
   * @param stepIndex The top-level step index withing the iterator.
   *
   * @return 32 bits as an integer that give information about the location 
   * path as a whole.
   *
   * @throws javax.xml.transform.TransformerException
   */
  private static int analyze(
          Compiler compiler, int stepOpCodePos, int stepIndex)
            throws javax.xml.transform.TransformerException
  {

    int stepType;
    int ops[] = compiler.getOpMap();
    int stepCount = 0;
    int analysisResult = 0x00000000;  // 32 bits of analysis

    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
    {
      stepCount++;

      // String namespace = compiler.getStepNS(stepOpCodePos);
      // boolean isNSWild = (null != namespace) 
      //                   ? namespace.equals(NodeTest.WILD) : false;
      // String localname = compiler.getStepLocalName(stepOpCodePos);
      // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false;
      boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos,
                                              stepType);

      if (predAnalysis)
        analysisResult |= BIT_PREDICATE;

      switch (stepType)
      {
      case OpCodes.OP_VARIABLE :
      case OpCodes.OP_EXTFUNCTION :
      case OpCodes.OP_FUNCTION :
      case OpCodes.OP_GROUP :
        analysisResult |= BIT_FILTER;
        break;
      case OpCodes.FROM_ROOT :
        analysisResult |= BIT_ROOT;
        break;
      case OpCodes.FROM_ANCESTORS :
        analysisResult |= BIT_ANCESTOR;
        break;
      case OpCodes.FROM_ANCESTORS_OR_SELF :
        analysisResult |= BIT_ANCESTOR_OR_SELF;
        break;
      case OpCodes.FROM_ATTRIBUTES :
        analysisResult |= BIT_ATTRIBUTE;
        break;
      case OpCodes.FROM_NAMESPACE :
        analysisResult |= BIT_NAMESPACE;
        break;
      case OpCodes.FROM_CHILDREN :
        analysisResult |= BIT_CHILD;
        break;
      case OpCodes.FROM_DESCENDANTS :
        analysisResult |= BIT_DESCENDANT;
        break;
      case OpCodes.FROM_DESCENDANTS_OR_SELF :
        // Use a special bit to to make sure we get the right analysis of "//foo".
        if(2 == stepCount && BIT_ROOT == analysisResult)
        {
          analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT;
        }
        analysisResult |= BIT_DESCENDANT_OR_SELF;
        break;
      case OpCodes.FROM_FOLLOWING :
        analysisResult |= BIT_DESCENDANT_OR_SELF;
        break;
      case OpCodes.FROM_FOLLOWING_SIBLINGS :
        analysisResult |= BIT_FOLLOWING_SIBLING;
        break;
      case OpCodes.FROM_PRECEDING :
        analysisResult |= BIT_PRECEDING;
        break;
      case OpCodes.FROM_PRECEDING_SIBLINGS :
        analysisResult |= BIT_PRECEDING_SIBLING;
        break;
      case OpCodes.FROM_PARENT :
        analysisResult |= BIT_PARENT;
        break;
      case OpCodes.FROM_SELF :
        analysisResult |= BIT_SELF;
        break;
      case OpCodes.MATCH_ATTRIBUTE :
        analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
        break;
      case OpCodes.MATCH_ANY_ANCESTOR :
        analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
        break;
      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
        analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT);
        break;
      default :
        throw new RuntimeException("Programmer's assertion: unknown opcode: "
                                   + stepType);
      }

      if (OpCodes.NODETYPE_NODE == ops[stepOpCodePos + 3])  // child::node()
      {
        analysisResult |= BIT_NODETEST_ANY;
      }

      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);

      if (stepOpCodePos < 0)
        break;
    }

    analysisResult |= (stepCount & BITS_COUNT);

    return analysisResult;
  }

  /**
   * Analyze a step and give information about it's predicates.  Right now this 
   * just returns true or false if the step has a predicate.
   *
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param opPos The opcode position for the step.
   * @param stepType The type of step, one of OP_GROUP, etc.
   *
   * @return true if step has a predicate.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
          throws javax.xml.transform.TransformerException
  {

    int argLen;

    switch (stepType)
    {
    case OpCodes.OP_VARIABLE :
    case OpCodes.OP_EXTFUNCTION :
    case OpCodes.OP_FUNCTION :
    case OpCodes.OP_GROUP :
      argLen = compiler.getArgLength(opPos);
      break;
    default :
      argLen = compiler.getArgLengthOfStep(opPos);
    }

    int pos = compiler.getFirstPredicateOpPos(opPos);
    int nPredicates = compiler.countPredicates(pos);

    return (nPredicates > 0) ? true : false;
  }

  /**
   * Create the proper Walker from the axes type.
   *
   * @param compiler non-null reference to compiler object that has processed 
   *                 the XPath operations into an opcode map.
   * @param opPos The opcode position for the step.
   * @param lpi The owning location path iterator.
   * @param analysis 32 bits of analysis, from which the type of AxesWalker 
   *                 may be influenced.
   *
   * @return non-null reference to AxesWalker derivative.
   * @throws RuntimeException if the input is bad.
   */
  private static AxesWalker createDefaultWalker(Compiler compiler, int opPos,
          LocPathIterator lpi, int analysis)
  {

    AxesWalker ai;
    int stepType = compiler.getOp(opPos);

    /*
    System.out.println("0: "+compiler.getOp(opPos));
    System.out.println("1: "+compiler.getOp(opPos+1));
    System.out.println("2: "+compiler.getOp(opPos+2));
    System.out.println("3: "+compiler.getOp(opPos+3));
    System.out.println("4: "+compiler.getOp(opPos+4));
    System.out.println("5: "+compiler.getOp(opPos+5));
    */
    boolean simpleInit = false;
    int totalNumberWalkers = (analysis & BITS_COUNT);
    boolean prevIsOneStepDown = true;

    switch (stepType)
    {
    case OpCodes.OP_VARIABLE :
    case OpCodes.OP_EXTFUNCTION :
    case OpCodes.OP_FUNCTION :
    case OpCodes.OP_GROUP :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  FilterExprWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new FilterExprWalker(lpi);
      simpleInit = true;
      break;
    case OpCodes.FROM_ROOT :
      if (0 == (analysis & ~(BIT_ROOT | BIT_CHILD | BIT_ATTRIBUTE | 
                             BIT_NAMESPACE | BIT_PREDICATE | BITS_COUNT)))
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  RootWalkerMultiStep: " + analysis
                             + ", " + compiler.toString());
                             
        ai = new RootWalkerMultiStep(lpi);
      }
      else
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  RootWalker: " + analysis
                             + ", " + compiler.toString());
        ai = new RootWalker(lpi);
      }
      break;
    case OpCodes.FROM_ANCESTORS :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  AncestorWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new AncestorWalker(lpi);
      break;
    case OpCodes.FROM_ANCESTORS_OR_SELF :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  AncestorOrSelfWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new AncestorOrSelfWalker(lpi);
      break;
    case OpCodes.FROM_ATTRIBUTES :
      if (1 == totalNumberWalkers)
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  AttributeWalkerOneStep: " + analysis
                             + ", " + compiler.toString());

        // TODO: We should be able to do this as long as this is 
        // the last step.
        ai = new AttributeWalkerOneStep(lpi);
      }
      else
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  AttributeWalker: " + analysis
                             + ", " + compiler.toString());
                             
        ai = new AttributeWalker(lpi);
      }
      break;
    case OpCodes.FROM_NAMESPACE :
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  NamespaceWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new NamespaceWalker(lpi);
      break;
    case OpCodes.FROM_CHILDREN :
      if (1 == totalNumberWalkers)
      {
        // I don't think this will ever happen any more.  -sb
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  ChildWalkerOneStep: " + analysis + ", "
                             + compiler.toString());

        ai = new ChildWalkerOneStep(lpi);
      }
      else
      {
        if (0 == (analysis & ~(BIT_ROOT | BIT_CHILD | BIT_ATTRIBUTE | 
                               BIT_NAMESPACE | BIT_PREDICATE | BITS_COUNT)))
        {
          if (DEBUG_WALKER_CREATION)
            System.out.println("new walker:  ChildWalkerMultiStep: " + analysis
                               + ", " + compiler.toString());

          ai = new ChildWalkerMultiStep(lpi);
        }
        else
        {
          if (DEBUG_WALKER_CREATION)
            System.out.println("new walker:  ChildWalker: " + analysis
                               + ", " + compiler.toString());
          ai = new ChildWalker(lpi);
        }
      }
      break;
    case OpCodes.FROM_DESCENDANTS :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  DescendantWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new DescendantWalker(lpi);
      break;
    case OpCodes.FROM_DESCENDANTS_OR_SELF :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  DescendantOrSelfWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new DescendantOrSelfWalker(lpi);
      break;
    case OpCodes.FROM_FOLLOWING :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  FollowingWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new FollowingWalker(lpi);
      break;
    case OpCodes.FROM_FOLLOWING_SIBLINGS :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  FollowingSiblingWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new FollowingSiblingWalker(lpi);
      break;
    case OpCodes.FROM_PRECEDING :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  PrecedingWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new PrecedingWalker(lpi);
      break;
    case OpCodes.FROM_PRECEDING_SIBLINGS :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  PrecedingSiblingWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new PrecedingSiblingWalker(lpi);
      break;
    case OpCodes.FROM_PARENT :
      prevIsOneStepDown = false;
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  ParentWalker: " + analysis
                           + ", " + compiler.toString());
      ai = new ParentWalker(lpi);
      break;
    case OpCodes.FROM_SELF :
      if (1 == totalNumberWalkers)
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  SelfWalkerOneStep: " + analysis
                             + ", " + compiler.toString());

        ai = new SelfWalkerOneStep(lpi);
      }
      else
      {
        if (DEBUG_WALKER_CREATION)
          System.out.println("new walker:  SelfWalker: " + analysis
                             + ", " + compiler.toString());
        ai = new SelfWalker(lpi);
      }
      break;
    case OpCodes.MATCH_ATTRIBUTE :
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  AttributeWalker(MATCH_ATTRIBUTE): " + analysis
                           + ", " + compiler.toString());
      ai = new AttributeWalker(lpi);
      break;
    case OpCodes.MATCH_ANY_ANCESTOR :
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  ChildWalker(MATCH_ANY_ANCESTOR): " + analysis
                           + ", " + compiler.toString());
      ai = new ChildWalker(lpi);
      break;
    case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
      if (DEBUG_WALKER_CREATION)
        System.out.println("new walker:  ChildWalker(MATCH_IMMEDIATE_ANCESTOR): " + analysis
                           + ", " + compiler.toString());
      ai = new ChildWalker(lpi);
      break;
    default :
      throw new RuntimeException("Programmer's assertion: unknown opcode: "
                                 + stepType);
    }

    if (simpleInit)
    {
      ai.initNodeTest(NodeFilter.SHOW_ALL);
    }
    else
    {
      int whatToShow = compiler.getWhatToShow(opPos);

      /*
      System.out.print("construct: ");
      NodeTest.debugWhatToShow(whatToShow);
      System.out.println("or stuff: "+(whatToShow & (NodeFilter.SHOW_ATTRIBUTE
                             | NodeFilter.SHOW_ELEMENT
                             | NodeFilter.SHOW_PROCESSING_INSTRUCTION)));
      */
      if ((0 == (whatToShow
                 & (NodeFilter.SHOW_ATTRIBUTE | NodeFilter.SHOW_ELEMENT
                    | NodeFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == NodeFilter.SHOW_ALL))
        ai.initNodeTest(whatToShow);
      else
      {
        ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
                        compiler.getStepLocalName(opPos));
      }
    }

    return ai;
  }

  /** Set to true for diagnostics about walker creation */
  static final boolean DEBUG_WALKER_CREATION = false;

  /** Set to true for diagnostics about iterator creation */
  static final boolean DEBUG_ITERATOR_CREATION = false;

  /**
   * First 8 bits are the number of top-level location steps.  Hopefully
   *  there will never be more that 255 location steps!!! 
   */
  public static final int BITS_COUNT = 0x000000FF;

  /** 4 bits are reserved for future use. */
  public static final int BITS_RESERVED = 0x00000F00;

  /** Bit is on if the expression contains a top-level predicate. */
  public static final int BIT_PREDICATE = (0x00001000);

  /** Bit is on if any of the walkers contain an ancestor step. */
  public static final int BIT_ANCESTOR = (0x00001000 << 1);

  /** Bit is on if any of the walkers contain an ancestor-or-self step. */
  public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);

  /** Bit is on if any of the walkers contain an attribute step. */
  public static final int BIT_ATTRIBUTE = (0x00001000 << 3);

  /** Bit is on if any of the walkers contain a child step. */
  public static final int BIT_CHILD = (0x00001000 << 4);

  /** Bit is on if any of the walkers contain a descendant step. */
  public static final int BIT_DESCENDANT = (0x00001000 << 5);

  /** Bit is on if any of the walkers contain a descendant-or-self step. */
  public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);

  /** Bit is on if any of the walkers contain a following step. */
  public static final int BIT_FOLLOWING = (0x00001000 << 7);

  /** Bit is on if any of the walkers contain a following-sibiling step. */
  public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);

  /** Bit is on if any of the walkers contain a namespace step. */
  public static final int BIT_NAMESPACE = (0x00001000 << 9);

  /** Bit is on if any of the walkers contain a parent step. */
  public static final int BIT_PARENT = (0x00001000 << 10);

  /** Bit is on if any of the walkers contain a preceding step. */
  public static final int BIT_PRECEDING = (0x00001000 << 11);

  /** Bit is on if any of the walkers contain a preceding-sibling step. */
  public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);

  /** Bit is on if any of the walkers contain a self step. */
  public static final int BIT_SELF = (0x00001000 << 13);

  /**
   * Bit is on if any of the walkers contain a filter (i.e. id(), extension
   *  function, etc.) step. 
   */
  public static final int BIT_FILTER = (0x00001000 << 14);

  /** Bit is on if any of the walkers contain a root step. */
  public static final int BIT_ROOT = (0x00001000 << 15);
  
  /** If any of these bits are on, the expression may likely traverse outside 
   *  the given subtree. */
  public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE 
                                                   = (BIT_NAMESPACE // ??
                                                    | BIT_PRECEDING_SIBLING
                                                    | BIT_PRECEDING
                                                    | BIT_FOLLOWING_SIBLING
                                                    | BIT_FOLLOWING
                                                    | BIT_PARENT // except parent of attrs.
                                                    | BIT_ANCESTOR_OR_SELF
                                                    | BIT_ANCESTOR
                                                    | BIT_FILTER
                                                    | BIT_ROOT);                                                    

  /**
   * Bit is on if any of the walkers can go backwards in document
   *  order from the context node. 
   */
  public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);

  /** Found "//foo" pattern */
  public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);

  /**
   * Bit is on if any of the walkers contain an node() test.  This is
   *  really only useful if the count is 1. 
   */
  public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
  
  // can't go higher than 18!

  /** Bit is on if the expression is a match pattern. */
  public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);

}
