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.BasisLibrary;
25import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
26import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
27import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
28import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
29
30/**
31 * Removes duplicates and sorts a source iterator. The nodes from the
32 * source are collected in an array upon calling setStartNode(). This
33 * array is later sorted and duplicates are ignored in next().
34 * @author G. Todd Miller
35 */
36public final class DupFilterIterator extends DTMAxisIteratorBase {
37
38    /**
39     * Reference to source iterator.
40     */
41    private DTMAxisIterator _source;
42
43    /**
44     * Array to cache all nodes from source.
45     */
46    private IntegerArray _nodes = new IntegerArray();
47
48    /**
49     * Index in _nodes array to current node.
50     */
51    private int _current = 0;
52
53    /**
54     * Cardinality of _nodes array.
55     */
56    private int _nodesSize = 0;
57
58    /**
59     * Last value returned by next().
60     */
61    private int _lastNext = END;
62
63    /**
64     * Temporary variable to store _lastNext.
65     */
66    private int _markedLastNext = END;
67
68    public DupFilterIterator(DTMAxisIterator source) {
69        _source = source;
70// System.out.println("DFI source = " + source + " this = " + this);
71
72        // Cache contents of id() or key() index right away. Necessary for
73        // union expressions containing multiple calls to the same index, and
74        // correct as well since start-node is irrelevant for id()/key() exrp.
75        if (source instanceof KeyIndex) {
76            setStartNode(DTMDefaultBase.ROOTNODE);
77        }
78    }
79
80    /**
81     * Set the start node for this iterator
82     * @param node The start node
83     * @return A reference to this node iterator
84     */
85    public DTMAxisIterator setStartNode(int node) {
86        if (_isRestartable) {
87            // KeyIndex iterators are always relative to the root node, so there
88            // is never any point in re-reading the iterator (and we SHOULD NOT).
89            boolean sourceIsKeyIndex = _source instanceof KeyIndex;
90
91            if (sourceIsKeyIndex
92                    && _startNode == DTMDefaultBase.ROOTNODE) {
93                return this;
94            }
95
96            if (node != _startNode) {
97                _source.setStartNode(_startNode = node);
98
99                _nodes.clear();
100                while ((node = _source.next()) != END) {
101                    _nodes.add(node);
102                }
103
104                // Nodes produced by KeyIndex are known to be in document order.
105                // Take advantage of it.
106                if (!sourceIsKeyIndex) {
107                    _nodes.sort();
108                }
109                _nodesSize = _nodes.cardinality();
110                _current = 0;
111                _lastNext = END;
112                resetPosition();
113            }
114        }
115        return this;
116    }
117
118    public int next() {
119        while (_current < _nodesSize) {
120            final int next = _nodes.at(_current++);
121            if (next != _lastNext) {
122                return returnNode(_lastNext = next);
123            }
124        }
125        return END;
126    }
127
128    public DTMAxisIterator cloneIterator() {
129        try {
130            final DupFilterIterator clone =
131                (DupFilterIterator) super.clone();
132            clone._nodes = (IntegerArray) _nodes.clone();
133            clone._source = _source.cloneIterator();
134            clone._isRestartable = false;
135            return clone.reset();
136        }
137        catch (CloneNotSupportedException e) {
138            BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
139                                      e.toString());
140            return null;
141        }
142    }
143
144    public void setRestartable(boolean isRestartable) {
145        _isRestartable = isRestartable;
146        _source.setRestartable(isRestartable);
147    }
148
149    public void setMark() {
150        _markedNode = _current;
151        _markedLastNext = _lastNext;    // Bugzilla 25924
152    }
153
154    public void gotoMark() {
155        _current = _markedNode;
156        _lastNext = _markedLastNext;    // Bugzilla 25924
157    }
158
159    public DTMAxisIterator reset() {
160        _current = 0;
161        _lastNext = END;
162        return resetPosition();
163    }
164}
165