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 org.apache.commons.jxpath.ri.EvalContext;
020    import org.apache.commons.jxpath.ri.compiler.NodeTest;
021    import org.apache.commons.jxpath.ri.model.NodePointer;
022    
023    /**
024     * EvalContext that walks the "ancestor::" and "ancestor-or-self::" axes.
025     *
026     * @author Dmitri Plotnikov
027     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
028     */
029    public class AncestorContext extends EvalContext {
030        private NodeTest nodeTest;
031        private boolean setStarted = false;
032        private NodePointer currentNodePointer;
033        private boolean includeSelf;
034    
035        /**
036         * Create a new AncestorContext.
037         * @param parentContext represents the previous step on the path
038         * @param  includeSelf differentiates between "ancestor::" and
039         *                     "ancestor-or-self::" axes
040         * @param nodeTest is the name of the element(s) we are looking for
041         */
042        public AncestorContext(
043            EvalContext parentContext,
044            boolean includeSelf,
045            NodeTest nodeTest) {
046            super(parentContext);
047            this.includeSelf = includeSelf;
048            this.nodeTest = nodeTest;
049        }
050    
051        public NodePointer getCurrentNodePointer() {
052            return currentNodePointer;
053        }
054    
055        public int getDocumentOrder() {
056            return -1;
057        }
058    
059        public void reset() {
060            super.reset();
061            setStarted = false;
062        }
063    
064        public boolean setPosition(int position) {
065            if (position < getCurrentPosition()) {
066                reset();
067            }
068    
069            while (getCurrentPosition() < position) {
070                if (!nextNode()) {
071                    return false;
072                }
073            }
074            return true;
075        }
076    
077        public boolean nextNode() {
078            if (!setStarted) {
079                setStarted = true;
080                currentNodePointer = parentContext.getCurrentNodePointer();
081                if (includeSelf && currentNodePointer.testNode(nodeTest)) {
082                    position++;
083                    return true;
084                }
085            }
086    
087            while (true) {
088                currentNodePointer = currentNodePointer.getImmediateParentPointer();
089    
090                if (currentNodePointer == null) {
091                    return false;
092                }
093    
094                if (currentNodePointer.testNode(nodeTest)) {
095                    position++;
096                    return true;
097                }
098            }
099        }
100    }