gt:         int n = nextNode();
context: /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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.
   */
  
  package com.sun.org.apache.xpath.internal.axes;
  
  import java.util.Vector;
  
  import com.sun.org.apache.xml.internal.dtm.DTM;
  import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  import com.sun.org.apache.xml.internal.dtm.DTMManager;
  import com.sun.org.apache.xml.internal.utils.NodeVector;
  import com.sun.org.apache.xpath.internal.NodeSetDTM;
  import com.sun.org.apache.xpath.internal.XPathContext;
  import com.sun.org.apache.xpath.internal.objects.XObject;
  
  /**
   * This class is the dynamic wrapper for a Xalan DTMIterator instance, and
   * provides random access capabilities.
   */
  public class NodeSequence extends XObject
    implements DTMIterator, Cloneable, PathComponent
  {
      static final long serialVersionUID = 3866261934726581044L;
    /** The index of the last node in the iteration. */
    protected int m_last = -1;
  
    /**
     * The index of the next node to be fetched.  Useful if this
     * is a cached iterator, and is being used as random access
     * NodeList.
     */
    protected int m_next = 0;
  
    /**
     * A cache of a list of nodes obtained from the iterator so far.
     * This list is appended to until the iterator is exhausted and
     * the cache is complete.
     * <p>
     * Multiple NodeSequence objects may share the same cache.
     */
    private IteratorCache m_cache;
  
    /**
     * If this iterator needs to cache nodes that are fetched, they
     * are stored in the Vector in the generic object.
     */
    protected NodeVector getVector() {
        NodeVector nv = (m_cache != null) ?  m_cache.getVector() : null;
        return nv;
    }
  
    /**
     * Get the cache (if any) of nodes obtained from
     * the iterator so far. Note that the cache keeps
     * growing until the iterator is walked to exhaustion,
     * at which point the cache is "complete".
     */
    private IteratorCache getCache() {
        return m_cache;
    }
  
    /**
     * Set the vector where nodes will be cached.
     */
    protected void SetVector(NodeVector v)
    {
          setObject(v);
    }
  
  
    /**
     * If the iterator needs to cache nodes as they are fetched,
     * then this method returns true.
     */
    public boolean hasCache()
    {
      final NodeVector nv = getVector();
          return (nv != null);
    }
  
    /**
     * If this NodeSequence has a cache, and that cache is
     * fully populated then this method returns true, otherwise
     * if there is no cache or it is not complete it returns false.
     */
    private boolean cacheComplete() {
        final boolean complete;
        if (m_cache != null) {
            complete = m_cache.isComplete();
        } else {
            complete = false;
        }
        return complete;
    }
  
    /**
     * If this NodeSequence has a cache, mark that it is complete.
     * This method should be called after the iterator is exhausted.
     */
    private void markCacheComplete() {
        NodeVector nv = getVector();
        if (nv != null) {
            m_cache.setCacheComplete(true);
        }
    }
  
  
    /**
     * The functional iterator that fetches nodes.
     */
    protected DTMIterator m_iter;
  
    /**
     * Set the functional iterator that fetches nodes.
     * @param iter The iterator that is to be contained.
     */
    public final void setIter(DTMIterator iter)
    {
          m_iter = iter;
    }
  
    /**
     * Get the functional iterator that fetches nodes.
     * @return The contained iterator.
     */
    public final DTMIterator getContainedIter()
    {
          return m_iter;
    }
  
    /**
     * The DTMManager to use if we're using a NodeVector only.
     * We may well want to do away with this, and store it in the NodeVector.
     */
    protected DTMManager m_dtmMgr;
  
    // ==== Constructors ====
  
    /**
     * Create a new NodeSequence from a (already cloned) iterator.
     *
     * @param iter Cloned (not static) DTMIterator.
     * @param context The initial context node.
     * @param xctxt The execution context.
     * @param shouldCacheNodes True if this sequence can random access.
     */
    private NodeSequence(DTMIterator iter, int context, XPathContext xctxt, boolean shouldCacheNodes)
    {
          setIter(iter);
          setRoot(context, xctxt);
          setShouldCacheNodes(shouldCacheNodes);
    }
  
    /**
     * Create a new NodeSequence from a (already cloned) iterator.
     *
     * @param nodeVector
     */
    public NodeSequence(Object nodeVector)
    {
          super(nodeVector);
      if (nodeVector instanceof NodeVector) {
          SetVector((NodeVector) nodeVector);
      }
          if(null != nodeVector)
          {
                  assertion(nodeVector instanceof NodeVector,
                          "Must have a NodeVector as the object for NodeSequence!");
                  if(nodeVector instanceof DTMIterator)
                  {
                          setIter((DTMIterator)nodeVector);
                          m_last = ((DTMIterator)nodeVector).getLength();
                  }
  
          }
    }
  
    /**
     * Construct an empty XNodeSet object.  This is used to create a mutable
     * nodeset to which random nodes may be added.
     */
    private NodeSequence(DTMManager dtmMgr)
    {
      super(new NodeVector());
      m_last = 0;
      m_dtmMgr = dtmMgr;
    }
  
  
    /**
     * Create a new NodeSequence in an invalid (null) state.
     */
    public NodeSequence()
    {
        return;
    }
  
  
    /**
     * @see DTMIterator#getDTM(int)
     */
    public DTM getDTM(int nodeHandle)
    {
          DTMManager mgr = getDTMManager();
          if(null != mgr)
          return getDTMManager().getDTM(nodeHandle);
      else
      {
          assertion(false, "Can not get a DTM Unless a DTMManager has been set!");
          return null;
      }
    }
  
    /**
     * @see DTMIterator#getDTMManager()
     */
    public DTMManager getDTMManager()
    {
      return m_dtmMgr;
    }
  
    /**
     * @see DTMIterator#getRoot()
     */
    public int getRoot()
    {
          if(null != m_iter)
          return m_iter.getRoot();
          else
          {
                  // NodeSetDTM will call this, and so it's not a good thing to throw
                  // an assertion here.
                  // assertion(false, "Can not get the root from a non-iterated NodeSequence!");
                  return DTM.NULL;
          }
    }
  
    /**
     * @see DTMIterator#setRoot(int, Object)
     */
    public void setRoot(int nodeHandle, Object environment)
    {
          // If root is DTM.NULL, then something's wrong with the context
          if (nodeHandle == DTM.NULL)
          {
              throw new RuntimeException("Unable to evaluate expression using " +
                      "this context");
          }
  
          if(null != m_iter)
          {
                  XPathContext xctxt = (XPathContext)environment;
                  m_dtmMgr = xctxt.getDTMManager();
                  m_iter.setRoot(nodeHandle, environment);
                  if(!m_iter.isDocOrdered())
                  {
                          if(!hasCache())
                                  setShouldCacheNodes(true);
                          runTo(-1);
                          m_next=0;
                  }
          }
          else
                  assertion(false, "Can not setRoot on a non-iterated NodeSequence!");
    }
  
    /**
     * @see DTMIterator#reset()
     */
    public void reset()
    {
          m_next = 0;
          // not resetting the iterator on purpose!!!
    }
  
    /**
     * @see DTMIterator#getWhatToShow()
     */
    public int getWhatToShow()
    {
      return hasCache() ? (DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE)
          : m_iter.getWhatToShow();
    }
  
    /**
     * @see DTMIterator#getExpandEntityReferences()
     */
    public boolean getExpandEntityReferences()
    {
          if(null != m_iter)
                  return m_iter.getExpandEntityReferences();
          else
          return true;
    }
  
    /**
     * @see DTMIterator#nextNode()
     */
    public int nextNode()
    {
      // If the cache is on, and the node has already been found, then
      // just return from the list.
      NodeVector vec = getVector();
      if (null != vec)
      {
          // There is a cache
          if(m_next < vec.size())
          {
              // The node is in the cache, so just return it.
                          int next = vec.elementAt(m_next);
                  m_next++;
                  return next;
          }
          else if(cacheComplete() || (-1 != m_last) || (null == m_iter))
          {
                  m_next++;
                  return DTM.NULL;
          }
      }
  
    if (null == m_iter)
      return DTM.NULL;
  
          int next = m_iter.nextNode();
      if(DTM.NULL != next)
      {
          if(hasCache())
          {
                  if(m_iter.isDocOrdered())
              {
                          getVector().addElement(next);
                          m_next++;
                  }
                  else
                  {
                          int insertIndex = addNodeInDocOrder(next);
                          if(insertIndex >= 0)
                                  m_next++;
                  }
          }
          else
                  m_next++;
      }
      else
      {
          // We have exhausted the iterator, and if there is a cache
          // it must have all nodes in it by now, so let the cache
          // know that it is complete.
          markCacheComplete();
  
          m_last = m_next;
          m_next++;
      }
  
      return next;
    }
  
    /**
     * @see DTMIterator#previousNode()
     */
    public int previousNode()
    {
          if(hasCache())
          {
                  if(m_next <= 0)
                          return DTM.NULL;
                  else
                  {
                          m_next--;
                          return item(m_next);
                  }
          }
          else
          {
              int n = m_iter.previousNode();
              m_next = m_iter.getCurrentPos();
              return m_next;
          }
    }
  
    /**
     * @see DTMIterator#detach()
     */
    public void detach()
    {
          if(null != m_iter)
                  m_iter.detach();
          super.detach();
    }
  
    /**
     * Calling this with a value of false will cause the nodeset
     * to be cached.
     * @see DTMIterator#allowDetachToRelease(boolean)
     */
    public void allowDetachToRelease(boolean allowRelease)
    {
          if((false == allowRelease) && !hasCache())
          {
                  setShouldCacheNodes(true);
          }
  
          if(null != m_iter)
                  m_iter.allowDetachToRelease(allowRelease);
          super.allowDetachToRelease(allowRelease);
    }
  
    /**
     * @see DTMIterator#getCurrentNode()
     */
    public int getCurrentNode()
    {
          if(hasCache())
          {
                  int currentIndex = m_next-1;
                  NodeVector vec = getVector();
                  if((currentIndex >= 0) && (currentIndex < vec.size()))
                          return vec.elementAt(currentIndex);
                  else
                          return DTM.NULL;
          }
  
          if(null != m_iter)
          {
          return m_iter.getCurrentNode();
          }
          else
                  return DTM.NULL;
    }
  
    /**
     * @see DTMIterator#isFresh()
     */
    public boolean isFresh()
    {
      return (0 == m_next);
    }
  
    /**
     * @see DTMIterator#setShouldCacheNodes(boolean)
     */
    public void setShouldCacheNodes(boolean b)
    {
      if (b)
      {
        if(!hasCache())
        {
          SetVector(new NodeVector());
        }
  //        else
  //          getVector().RemoveAllNoClear();  // Is this good?
      }
      else
        SetVector(null);
    }
  
    /**
     * @see DTMIterator#isMutable()
     */
    public boolean isMutable()
    {
      return hasCache(); // though may be surprising if it also has an iterator!
    }
  
    /**
     * @see DTMIterator#getCurrentPos()
     */
    public int getCurrentPos()
    {
      return m_next;
    }
  
    /**
     * @see DTMIterator#runTo(int)
     */
    public void runTo(int index)
    {
      int n;
  
      if (-1 == index)
      {
        int pos = m_next;
        while (DTM.NULL != (n = nextNode()));
        m_next = pos;
      }
      else if(m_next == index)
      {
        return;
      }
      else if(hasCache() && index < getVector().size())
      {
        m_next = index;
      }
      else if((null == getVector()) && (index < m_next))
      {
        while ((m_next >= index) && DTM.NULL != (n = previousNode()));
      }
      else
      {
        while ((m_next < index) && DTM.NULL != (n = nextNode()));
      }
  
    }
  
    /**
     * @see DTMIterator#setCurrentPos(int)
     */
    public void setCurrentPos(int i)
    {
          runTo(i);
    }
  
    /**
     * @see DTMIterator#item(int)
     */
    public int item(int index)
    {
          setCurrentPos(index);
  