    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *     http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.jxpath.ri.axes;
    018
    019    import java.util.Stack;
    020
    021    import org.apache.commons.jxpath.ri.EvalContext;
    022    import org.apache.commons.jxpath.ri.compiler.NodeTest;
    023    import org.apache.commons.jxpath.ri.model.NodeIterator;
    024    import org.apache.commons.jxpath.ri.model.NodePointer;
    025
    026    /**
    027     * EvalContext that walks the "preceding::" and "following::" axes.
    028     *
    029     * @author Dmitri Plotnikov
    030     * @version $Revision: 670727 $ $Date: 2008-06-23 15:10:38 -0500 (Mon, 23 Jun 2008) $
    031     */
    032    public class PrecedingOrFollowingContext extends EvalContext {
    033        private NodeTest nodeTest;
    034        private boolean setStarted = false;
    035        private Stack stack = null;
    036        private NodePointer currentNodePointer;
    037        private NodePointer currentRootLocation;
    038        private boolean reverse;
    039
    040        /**
    041         * Create a new PrecedingOrFollowingContext.
    042         * @param parentContext parent context
    043         * @param nodeTest test
    044         * @param reverse whether to iterate in reverse order
    045         */
    046        public PrecedingOrFollowingContext(
    047            EvalContext parentContext,
    048            NodeTest nodeTest,
    049            boolean reverse) {
    050            super(parentContext);
    051            this.nodeTest = nodeTest;
    052            this.reverse = reverse;
    053        }
    054
    055        public NodePointer getCurrentNodePointer() {
    056            return currentNodePointer;
    057        }
    058
    059        public int getDocumentOrder() {
    060            return reverse ? -1 : 1;
    061        }
    062
    063        public void reset() {
    064            super.reset();
    065            setStarted = false;
    066        }
    067
    068        public boolean setPosition(int position) {
    069            if (position < this.position) {
    070                reset();
    071            }
    072
    073            while (this.position < position) {
    074                if (!nextNode()) {
    075                    return false;
    076                }
    077            }
    078            return true;
    079        }
    080
    081        public boolean nextNode() {
    082            if (!setStarted) {
    083                setStarted = true;
    084                if (stack == null) {
    085                    stack = new Stack();
    086                }
    087                else {
    088                    stack.clear();
    089                }
    090                currentRootLocation = parentContext.getCurrentNodePointer();
    091                NodePointer parent = currentRootLocation.getParent();
    092                if (parent != null) {
    093                    // TBD: check type
    094                    stack.push(
    095                        parent.childIterator(null, reverse, currentRootLocation));
    096                }
    097            }
    098
    099            while (true) {
    100                if (stack.isEmpty()) {
    101                    currentRootLocation = currentRootLocation.getParent();
    102
    103                    if (currentRootLocation == null
    104                        || currentRootLocation.isRoot()) {
    105                        break;
    106                    }
    107
    108                    NodePointer parent = currentRootLocation.getParent();
    109                    if (parent != null) {
    110                        stack.push(
    111                            parent.childIterator(
    112                                null,
    113                                reverse,
    114                                currentRootLocation));
    115                    }
    116                }
    117
    118                while (!stack.isEmpty()) {
    119                    if (!reverse) {
    120                        NodeIterator it = (NodeIterator) stack.peek();
    121                        if (it.setPosition(it.getPosition() + 1)) {
    122                            currentNodePointer = it.getNodePointer();
    123                            if (!currentNodePointer.isLeaf()) {
    124                                stack.push(
    125                                    currentNodePointer.childIterator(
    126                                        null,
    127                                        reverse,
    128                                        null));
    129                            }
    130                            if (currentNodePointer.testNode(nodeTest)) {
    131                                super.setPosition(getCurrentPosition() + 1);
    132                                return true;
    133                            }
    134                        }
    135                        else {
    136                            // We get here only if the name test failed
    137                            // and the iterator ended
    138                            stack.pop();
    139                        }
    140                    }
    141                    else {
    142                        NodeIterator it = (NodeIterator) stack.peek();
    143                        if (it.setPosition(it.getPosition() + 1)) {
    144                            currentNodePointer = it.getNodePointer();
    145                            if (!currentNodePointer.isLeaf()) {
    146                                stack.push(
    147                                    currentNodePointer.childIterator(
    148                                        null,
    149                                        reverse,
    150                                        null));
    151                            }
    152                            else if (currentNodePointer.testNode(nodeTest)) {
    153                                super.setPosition(getCurrentPosition() + 1);
    154                                return true;
    155                            }
    156                        }
    157                        else {
    158                            stack.pop();
    159                            if (!stack.isEmpty()) {
    160                                it = (NodeIterator) stack.peek();
    161                                currentNodePointer = it.getNodePointer();
    162                                if (currentNodePointer.testNode(nodeTest)) {
    163                                    super.setPosition(getCurrentPosition() + 1);
    164                                    return true;
    165                                }
    166                            }
    167                        }
    168                    }
    169                }
    170            }
    171            return false;
    172        }
    173    }