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.collections.iterators;
018    
019    import java.util.ListIterator;
020    import java.util.NoSuchElementException;
021    
022    import org.apache.commons.collections.ResettableListIterator;
023    
024    /**
025     * Implements a {@link ListIterator} over an array of objects.
026     * <p>
027     * This iterator does not support {@link #add} or {@link #remove}, as the object array 
028     * cannot be structurally modified. The {@link #set} method is supported however.
029     * <p>
030     * The iterator implements a {@link #reset} method, allowing the reset of the iterator
031     * back to the start if required.
032     *
033     * @see org.apache.commons.collections.iterators.ObjectArrayIterator
034     * @see java.util.Iterator
035     * @see java.util.ListIterator
036     *
037     * @since Commons Collections 3.0
038     * @version $Revision: 647116 $ $Date: 2008-04-11 12:23:08 +0100 (Fri, 11 Apr 2008) $
039     * 
040     * @author Neil O'Toole
041     * @author Stephen Colebourne
042     * @author Phil Steitz
043     */
044    public class ObjectArrayListIterator extends ObjectArrayIterator
045            implements ListIterator, ResettableListIterator {
046    
047        /**
048         * Holds the index of the last item returned by a call to <code>next()</code> 
049         * or <code>previous()</code>. This is set to <code>-1</code> if neither method
050         * has yet been invoked. <code>lastItemIndex</code> is used to to implement the
051         * {@link #set} method.
052         */
053        protected int lastItemIndex = -1;
054    
055        /**
056         * Constructor for use with <code>setArray</code>.
057         * <p>
058         * Using this constructor, the iterator is equivalent to an empty iterator
059         * until {@link #setArray} is  called to establish the array to iterate over.
060         */
061        public ObjectArrayListIterator() {
062            super();
063        }
064    
065        /**
066         * Constructs an ObjectArrayListIterator that will iterate over the values in the
067         * specified array.
068         *
069         * @param array the array to iterate over
070         * @throws NullPointerException if <code>array</code> is <code>null</code>
071         */
072        public ObjectArrayListIterator(Object[] array) {
073            super(array);
074        }
075    
076        /**
077         * Constructs an ObjectArrayListIterator that will iterate over the values in the
078         * specified array from a specific start index.
079         *
080         * @param array  the array to iterate over
081         * @param start  the index to start iterating at
082         * @throws NullPointerException if <code>array</code> is <code>null</code>
083         * @throws IndexOutOfBoundsException if the start index is out of bounds
084         */
085        public ObjectArrayListIterator(Object[] array, int start) {
086            super(array, start);
087        }
088        
089        /**
090         * Construct an ObjectArrayListIterator that will iterate over a range of values 
091         * in the specified array.
092         *
093         * @param array  the array to iterate over
094         * @param start  the index to start iterating at
095         * @param end  the index (exclusive) to finish iterating at
096         * @throws IndexOutOfBoundsException if the start or end index is out of bounds
097         * @throws IllegalArgumentException if end index is before the start
098         * @throws NullPointerException if <code>array</code> is <code>null</code>
099         */
100        public ObjectArrayListIterator(Object[] array, int start, int end) {
101            super(array, start, end);
102        }
103    
104        // ListIterator interface
105        //-------------------------------------------------------------------------
106    
107        /**
108         * Returns true if there are previous elements to return from the array.
109         *
110         * @return true if there is a previous element to return
111         */
112        public boolean hasPrevious() {
113            return (this.index > this.startIndex);
114        }
115    
116        /**
117         * Gets the previous element from the array.
118         * 
119         * @return the previous element
120         * @throws NoSuchElementException if there is no previous element
121         */
122        public Object previous() {
123            if (hasPrevious() == false) {
124                throw new NoSuchElementException();
125            }
126            this.lastItemIndex = --this.index;
127            return this.array[this.index];
128        }
129    
130        /**
131         * Gets the next element from the array.
132         * 
133         * @return the next element
134         * @throws NoSuchElementException if there is no next element
135         */
136        public Object next() {
137            if (hasNext() == false) {
138                throw new NoSuchElementException();
139            }
140            this.lastItemIndex = this.index;
141            return this.array[this.index++];
142        }
143    
144        /**
145         * Gets the next index to be retrieved.
146         * 
147         * @return the index of the item to be retrieved next
148         */
149        public int nextIndex() {
150            return this.index - this.startIndex;
151        }
152    
153        /**
154         * Gets the index of the item to be retrieved if {@link #previous()} is called.
155         * 
156         * @return the index of the item to be retrieved next
157         */
158        public int previousIndex() {
159            return this.index - this.startIndex - 1;
160        }
161    
162        /**
163         * This iterator does not support modification of its backing array's size, and so will
164         * always throw an {@link UnsupportedOperationException} when this method is invoked.
165         *
166         * @param obj  the object to add
167         * @throws UnsupportedOperationException always thrown.
168         */
169        public void add(Object obj) {
170            throw new UnsupportedOperationException("add() method is not supported");
171        }
172    
173        /**
174         * Sets the element under the cursor.
175         * <p>
176         * This method sets the element that was returned by the last call 
177         * to {@link #next()} of {@link #previous()}. 
178         * 
179         * <b>Note:</b> {@link ListIterator} implementations that support <code>add()</code>
180         * and <code>remove()</code> only allow <code>set()</code> to be called once per call 
181         * to <code>next()</code> or <code>previous</code> (see the {@link ListIterator}
182         * javadoc for more details). Since this implementation does not support 
183         * <code>add()</code> or <code>remove()</code>, <code>set()</code> may be
184         * called as often as desired.
185         * 
186         * @param obj  the object to set into the array
187         * @throws IllegalStateException if next() has not yet been called.
188         * @throws ClassCastException if the object type is unsuitable for the array
189         */
190        public void set(Object obj) {
191            if (this.lastItemIndex == -1) {
192                throw new IllegalStateException("must call next() or previous() before a call to set()");
193            }
194    
195            this.array[this.lastItemIndex] = obj;
196        }
197    
198        /**
199         * Resets the iterator back to the start index.
200         */
201        public void reset() {
202            super.reset();
203            this.lastItemIndex = -1;
204        }
205    
206    }