1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xalan.internal.xsltc.dom;
23
24import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
25import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
26import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
27import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
28import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
29
30/**
31 * Iterators of this kind use a CurrentNodeListFilter to filter a subset of
32 * nodes from a source iterator. For each node from the source, the boolean
33 * method CurrentNodeListFilter.test() is called.
34 *
35 * All nodes from the source are read into an array upon calling setStartNode()
36 * (this is needed to determine the value of last, a parameter to
37 * CurrentNodeListFilter.test()). The method getLast() returns the last element
38 * after applying the filter.
39 * @author Jacek Ambroziak
40 * @author Santiago Pericas-Geertsen
41 * @author Morten Jorgensen
42 */
43
44public final class CurrentNodeListIterator extends DTMAxisIteratorBase {
45    /**
46     * A flag indicating if nodes are returned in document order.
47     */
48    private boolean _docOrder;
49
50    /**
51     * The source for this iterator.
52     */
53    private DTMAxisIterator _source;
54
55    /**
56     * A reference to a filter object.
57     */
58    private final CurrentNodeListFilter _filter;
59
60    /**
61     * An integer array to store nodes from source iterator.
62     */
63    private IntegerArray _nodes = new IntegerArray();
64
65    /**
66     * Index in _nodes of the next node to filter.
67     */
68    private int _currentIndex;
69
70    /**
71     * The current node in the stylesheet at the time of evaluation.
72     */
73    private final int _currentNode;
74
75    /**
76     * A reference to the translet.
77     */
78    private AbstractTranslet _translet;
79
80    public CurrentNodeListIterator(DTMAxisIterator source,
81                                   CurrentNodeListFilter filter,
82                                   int currentNode,
83                                   AbstractTranslet translet)
84    {
85        this(source, !source.isReverse(), filter, currentNode, translet);
86    }
87
88    public CurrentNodeListIterator(DTMAxisIterator source, boolean docOrder,
89                                   CurrentNodeListFilter filter,
90                                   int currentNode,
91                                   AbstractTranslet translet)
92    {
93        _source = source;
94        _filter = filter;
95        _translet = translet;
96        _docOrder = docOrder;
97        _currentNode = currentNode;
98    }
99
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}
200