    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.axes;
    17
    18  import java.util.Stack;
    19
    20  import org.apache.commons.jxpath.ri.EvalContext;
    21  import org.apache.commons.jxpath.ri.compiler.NodeTest;
    22  import org.apache.commons.jxpath.ri.model.NodeIterator;
    23  import org.apache.commons.jxpath.ri.model.NodePointer;
    24  import org.apache.commons.jxpath.ri.model.beans.PropertyIterator;
    25
    26  /***
    27   * EvalContext that walks the "preceding::" and "following::" axes.
    28   *
    29   * @author Dmitri Plotnikov
    30   * @version $Revision: 1.15 $ $Date: 2004/03/25 03:49:50 $
    31   */
    32  public class PrecedingOrFollowingContext extends EvalContext {
    33      private NodeTest nodeTest;
    34      private boolean setStarted = false;
    35      private boolean started = false;
    36      private Stack stack;
    37      private Stack nameStack;
    38      private NodePointer currentNodePointer;
    39      private NodePointer currentRootLocation;
    40      private boolean reverse;
    41
    42      public PrecedingOrFollowingContext(
    43          EvalContext parentContext,
    44          NodeTest nodeTest,
    45          boolean reverse)
    46      {
    47          super(parentContext);
    48          this.nodeTest = nodeTest;
    49          this.reverse = reverse;
    50      }
    51
    52      public NodePointer getCurrentNodePointer() {
    53          return currentNodePointer;
    54      }
    55
    56      public int getDocumentOrder() {
    57          return reverse ? -1 : 1;
    58      }
    59
    60      public void reset() {
    61          super.reset();
    62          stack = new Stack();
    63          setStarted = false;
    64      }
    65
    66      public boolean setPosition(int position) {
    67          if (position < this.position) {
    68              reset();
    69          }
    70
    71          while (this.position < position) {
    72              if (!nextNode()) {
    73                  return false;
    74              }
    75          }
    76          return true;
    77      }
    78
    79      public boolean nextNode() {
    80          if (!setStarted) {
    81              setStarted = true;
    82              currentRootLocation = parentContext.getCurrentNodePointer();
    83              NodePointer parent = currentRootLocation.getParent();
    84              if (parent != null) {
    85                  // TBD: check type
    86                  stack.push(
    87                      parent.childIterator(null, reverse, currentRootLocation));
    88              }
    89          }
    90
    91          while (true) {
    92              if (stack.isEmpty()) {
    93                  currentRootLocation = currentRootLocation.getParent();
    94
    95                  if (currentRootLocation == null
    96                      || currentRootLocation.isRoot()) {
    97                      break;
    98                  }
    99
    100                 NodePointer parent = currentRootLocation.getParent();
    101                 if (parent != null) {
    102                     stack.push(
    103                         parent.childIterator(
    104                             null,
    105                             reverse,
    106                             currentRootLocation));
    107                 }
    108             }
    109
    110             while (!stack.isEmpty()) {
    111                 if (!reverse) {
    112                     NodeIterator it = (NodeIterator) stack.peek();
    113                     if (it.setPosition(it.getPosition() + 1)) {
    114                         currentNodePointer = it.getNodePointer();
    115                         if (!currentNodePointer.isLeaf()) {
    116                             stack.push(
    117                                 currentNodePointer.childIterator(
    118                                     null,
    119                                     reverse,
    120                                     null));
    121                         }
    122                         if (currentNodePointer.testNode(nodeTest)) {
    123                             super.setPosition(getCurrentPosition() + 1);
    124                             return true;
    125                         }
    126                     }
    127                     else {
    128                         // We get here only if the name test failed
    129                         // and the iterator ended
    130                         stack.pop();
    131                     }
    132                 }
    133                 else {
    134                     NodeIterator it = (NodeIterator) stack.peek();
    135                     if (it.setPosition(it.getPosition() + 1)) {
    136                         currentNodePointer = it.getNodePointer();
    137                         if (!currentNodePointer.isLeaf()) {
    138                             stack.push(
    139                                 currentNodePointer.childIterator(
    140                                     null,
    141                                     reverse,
    142                                     null));
    143                         }
    144                         else if (currentNodePointer.testNode(nodeTest)) {
    145                             super.setPosition(getCurrentPosition() + 1);
    146                             return true;
    147                         }
    148                     }
    149                     else {
    150                         stack.pop();
    151                         if (!stack.isEmpty()) {
    152                             it = (PropertyIterator) stack.peek();
    153                             currentNodePointer = it.getNodePointer();
    154                             if (currentNodePointer.testNode(nodeTest)) {
    155                                 super.setPosition(getCurrentPosition() + 1);
    156                                 return true;
    157                             }
    158                         }
    159                     }
    160                 }
    161             }
    162         }
    163         return false;
    164     }
    165 }