001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: CurrentNodeListIterator.java 468651 2006-10-28 07:04:25Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.dom;
023    
024    import org.apache.xalan.xsltc.runtime.AbstractTranslet;
025    import org.apache.xalan.xsltc.runtime.BasisLibrary;
026    import org.apache.xalan.xsltc.util.IntegerArray;
027    import org.apache.xml.dtm.DTMAxisIterator;
028    import org.apache.xml.dtm.ref.DTMAxisIteratorBase;
029    
030    /**
031     * Iterators of this kind use a CurrentNodeListFilter to filter a subset of 
032     * nodes from a source iterator. For each node from the source, the boolean 
033     * method CurrentNodeListFilter.test() is called. 
034     *
035     * All nodes from the source are read into an array upon calling setStartNode() 
036     * (this is needed to determine the value of last, a parameter to 
037     * CurrentNodeListFilter.test()). The method getLast() returns the last element 
038     * after applying the filter.
039     * @author Jacek Ambroziak
040     * @author Santiago Pericas-Geertsen
041     * @author Morten Jorgensen
042     */
043    
044    public final class CurrentNodeListIterator extends DTMAxisIteratorBase {
045        /**
046         * A flag indicating if nodes are returned in document order.
047         */
048        private boolean _docOrder;
049    
050        /**
051         * The source for this iterator.
052         */
053        private DTMAxisIterator _source;
054    
055        /**
056         * A reference to a filter object.
057         */
058        private final CurrentNodeListFilter _filter;
059    
060        /**
061         * An integer array to store nodes from source iterator.
062         */
063        private IntegerArray _nodes = new IntegerArray();
064            
065        /**
066         * Index in _nodes of the next node to filter.
067         */
068        private int _currentIndex;
069            
070        /**
071         * The current node in the stylesheet at the time of evaluation.
072         */
073        private final int _currentNode;
074    
075        /**
076         * A reference to the translet.
077         */
078        private AbstractTranslet _translet;
079    
080        public CurrentNodeListIterator(DTMAxisIterator source, 
081                                       CurrentNodeListFilter filter,
082                                       int currentNode,
083                                       AbstractTranslet translet) 
084        {
085            this(source, !source.isReverse(), filter, currentNode, translet);
086        }
087    
088        public CurrentNodeListIterator(DTMAxisIterator source, boolean docOrder,
089                                       CurrentNodeListFilter filter,
090                                       int currentNode,
091                                       AbstractTranslet translet) 
092        {
093            _source = source;
094            _filter = filter;
095            _translet = translet;
096            _docOrder = docOrder;
097            _currentNode = currentNode;
098        }
099    
100        public DTMAxisIterator forceNaturalOrder() {
101            _docOrder = true;
102            return this;
103        }
104    
105        public void setRestartable(boolean isRestartable) {
106            _isRestartable = isRestartable;
107            _source.setRestartable(isRestartable);
108        }
109    
110        public boolean isReverse() {
111            return !_docOrder;
112        }
113    
114        public DTMAxisIterator cloneIterator() {
115            try {
116                final CurrentNodeListIterator clone =
117                    (CurrentNodeListIterator) super.clone();
118                clone._nodes = (IntegerArray) _nodes.clone();
119                clone._source = _source.cloneIterator();
120                clone._isRestartable = false;
121                return clone.reset();
122            }
123            catch (CloneNotSupportedException e) {
124                BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
125                                          e.toString());
126                return null;
127            }
128        }
129        
130        public DTMAxisIterator reset() {
131            _currentIndex = 0;
132            return resetPosition();
133        }
134    
135        public int next() {
136            final int last = _nodes.cardinality();
137            final int currentNode = _currentNode;
138            final AbstractTranslet translet = _translet;
139    
140            for (int index = _currentIndex; index < last; ) {
141                final int position = _docOrder ? index + 1 : last - index;
142                final int node = _nodes.at(index++);        // note increment
143    
144                if (_filter.test(node, position, last, currentNode, translet,
145                                 this)) {
146                    _currentIndex = index;
147                    return returnNode(node);
148                }
149            }
150            return END;
151        }
152    
153        public DTMAxisIterator setStartNode(int node) {
154            if (_isRestartable) {
155                _source.setStartNode(_startNode = node);
156    
157                _nodes.clear();
158                while ((node = _source.next()) != END) {
159                    _nodes.add(node);
160                }
161                _currentIndex = 0;
162                resetPosition();
163            }
164            return this;
165        }
166            
167        public int getLast() {
168            if (_last == -1) {
169                _last = computePositionOfLast();
170            }
171            return _last;
172        }
173    
174        public void setMark() {
175            _markedNode = _currentIndex;
176        }
177    
178        public void gotoMark() {
179            _currentIndex = _markedNode;
180        }
181    
182        private int computePositionOfLast() {
183            final int last = _nodes.cardinality();
184            final int currNode = _currentNode;
185            final AbstractTranslet translet = _translet;
186    
187            int lastPosition = _position;
188            for (int index = _currentIndex; index < last; ) {
189                final int position = _docOrder ? index + 1 : last - index;
190                int nodeIndex = _nodes.at(index++);         // note increment
191    
192                if (_filter.test(nodeIndex, position, last, currNode, translet,
193                                 this)) {
194                    lastPosition++;
195                }
196            }
197            return lastPosition;
198        }
199    }