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
007     *   "License"); you may not use this file except in compliance
008     *   with the License.  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,
013     *   software distributed under the License is distributed on an
014     *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *   KIND, either express or implied.  See the License for the
016     *   specific language governing permissions and limitations
017     *   under the License.
018     *
019     */
020    package org.apache.directory.server.core.avltree;
021    
022    import org.apache.directory.shared.ldap.cursor.AbstractCursor;
023    import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
024    
025    
026    
027    
028    /**
029     * A Cursor for an ArrayTree.
030     *
031     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
032     * @version $Rev$, $Date$
033     */
034    public class ArrayTreeCursor<K> extends AbstractCursor<K>
035    {
036        /** The underlying ArrayTree */
037        private ArrayTree<K> array;
038        
039        /** The current node */
040        private K node;
041        
042        /** A flag set to true if we are pointing to a node */
043        private boolean onNode = false;
044        
045        /** A flag to tell if we are after the last node */
046        private boolean isAfterLast = false;
047    
048        /** A flag to tell if we are before the first node */
049        private boolean isBeforeFirst = true;
050        
051        /** The current position in the array */
052        private int current;
053     
054        
055        /**
056         * Create a cursor on an ArrayTree
057         * @param array The array we want a cursor for
058         */
059        public ArrayTreeCursor( ArrayTree<K> array )
060        {
061            this.array = array;
062            current = -1;
063        }
064    
065        
066        /**
067         * {@inheritDoc}
068         */
069        public void after( K element ) throws Exception 
070        {
071            checkNotClosed( "after" );
072    
073            if ( element == null )
074            {
075                afterLast();
076                return;
077            }
078    
079            int found = array.getAfterPosition( element );
080            
081            if ( found == -1 )
082            {
083                // As the element has not been found, we move after the last
084                // position
085                afterLast();
086                return;
087            }
088    
089            // The element has been found, we have to pick the node,
090            // set the current position, and update the flags.
091            current = found;
092            //node = array.get( current );
093            isAfterLast = false;
094            isBeforeFirst = false;
095            onNode = false;
096        }
097    
098    
099        /**
100         * {@inheritDoc}
101         */
102        public void afterLast() throws Exception 
103        {
104            checkNotClosed( "afterLast" );
105            
106            current = array.size() - 1;
107            node = array.getLast();
108            isBeforeFirst = false;
109            isAfterLast = true;
110            onNode = false;
111        }
112    
113    
114        /**
115         * {@inheritDoc}
116         */
117        public boolean available()
118        {
119            return onNode;
120        }
121    
122    
123        /**
124         * {@inheritDoc}
125         */
126        public void before( K element ) throws Exception 
127        {
128            checkNotClosed( "before" );
129    
130            if ( element == null )
131            {
132                beforeFirst();
133                return;
134            }
135    
136            int found = array.getBeforePosition( element );
137    
138            // If the element has not been found, move to the
139            // first position
140            if ( found < 0 )
141            {
142                beforeFirst();
143                return;
144            }
145            
146            current = found;
147            isAfterLast = false;
148            isBeforeFirst = false;
149            onNode = true;
150            node = array.get( current );
151        }
152    
153    
154        /**
155         * {@inheritDoc}
156         */
157        public void beforeFirst() throws Exception 
158        {
159            checkNotClosed( "beforeFirst" );
160            
161            current = 0;
162            node = array.getFirst();
163            isBeforeFirst = true;
164            isAfterLast = false;
165            onNode = false;
166        }
167    
168    
169        /**
170         * {@inheritDoc}
171         */
172        public boolean first() throws Exception 
173        {
174            checkNotClosed( "first" );
175            
176            current = 0;
177            node = array.getFirst();
178            isBeforeFirst = false;
179            isAfterLast = false;
180            return onNode = node != null;
181        }
182    
183    
184        /**
185         * {@inheritDoc}
186         */
187        public K get() throws Exception 
188        {
189            checkNotClosed( "get" );
190            
191            if ( onNode )
192            {
193                return node;
194            }
195            
196            throw new InvalidCursorPositionException();
197        }
198    
199    
200        /**
201         * {@inheritDoc}
202         */
203        public boolean isElementReused()
204        {
205            return true;
206        }
207    
208    
209        /**
210         * {@inheritDoc}
211         */
212        public boolean last() throws Exception 
213        {
214            checkNotClosed( "last" );
215    
216            current = array.size() - 1;
217            node = array.getLast();
218            isBeforeFirst = false;
219            isAfterLast = false;
220            return onNode = node != null;
221        }
222    
223    
224        /**
225         * {@inheritDoc}
226         */
227        public boolean next() throws Exception 
228        {
229            checkNotClosed( "next" );
230            
231            // If the array is empty, return false
232            if ( array.size() == 0 )
233            {
234                return false;
235            }
236            
237            // If we are at the beginning
238            if ( isBeforeFirst ) 
239            {
240                current = 0;
241                node = array.getFirst();
242                isBeforeFirst = false;
243                isAfterLast = false;
244                onNode = node != null;
245                return onNode;
246            }
247            
248            if ( isAfterLast )
249            {
250                return false;
251            }
252    
253            if ( onNode )
254            {
255                current++;
256                
257                if ( current == array.size() )
258                {
259                    afterLast();
260                    return false;
261                }
262            }
263            
264            node = array.get( current );
265            onNode = node != null;
266            
267            return onNode;
268        }
269    
270    
271        /**
272         * {@inheritDoc}
273         */
274        public boolean previous() throws Exception
275        {
276            checkNotClosed( "previous" );
277            
278            if ( array.size() == 0 )
279            {
280                return false;
281            }
282            
283            if ( isBeforeFirst )
284            {
285                return false;
286            }
287    
288            if ( isAfterLast )
289            {
290                current = array.size() - 1;
291                node = array.getLast();
292                isBeforeFirst = false;
293                isAfterLast = false;
294                return onNode = node != null;
295            }
296    
297            if ( onNode )
298            {
299                current--;
300        
301                if ( current < 0 )
302                {
303                    beforeFirst();
304                    return false;
305                }
306            }
307            
308            node = array.get( current );
309            onNode = node != null;
310            
311            return onNode;
312        }
313    }