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.List;
020    import java.util.ListIterator;
021    
022    import org.apache.commons.collections.ResettableListIterator;
023    
024    /**
025     * Iterates backwards through a List, starting with the last element
026     * and continuing to the first. This is useful for looping around
027     * a list in reverse order without needing to actually reverse the list.
028     * <p>
029     * The first call to <code>next()</code> will return the last element
030     * from the list, and so on. The <code>hasNext()</code> method works
031     * in concert with the <code>next()</code> method as expected.
032     * However, the <code>nextIndex()</code> method returns the correct
033     * index in the list, thus it starts high and reduces as the iteration
034     * continues. The previous methods work similarly.
035     *
036     * @author Serge Knystautas
037     * @author Stephen Colebourne
038     * @since Commons Collections 3.2
039     * @version $Revision: $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
040     */
041    public class ReverseListIterator implements ResettableListIterator {
042    
043        /** The list being wrapped. */
044        private final List list;
045        /** The list iterator being wrapped. */
046        private ListIterator iterator;
047        /** Flag to indicate if updating is possible at the moment. */
048        private boolean validForUpdate = true;
049    
050        /**
051         * Constructor that wraps a list.
052         *
053         * @param list  the list to create a reversed iterator for
054         * @throws NullPointerException if the list is null
055         */
056        public ReverseListIterator(List list) {
057            super();
058            this.list = list;
059            iterator = list.listIterator(list.size());
060        }
061    
062        //-----------------------------------------------------------------------
063        /**
064         * Checks whether there is another element.
065         *
066         * @return true if there is another element
067         */
068        public boolean hasNext() {
069            return iterator.hasPrevious();
070        }
071    
072        /**
073         * Gets the next element.
074         * The next element is the previous in the list.
075         *
076         * @return the next element in the iterator
077         */
078        public Object next() {
079            Object obj = iterator.previous();
080            validForUpdate = true;
081            return obj;
082        }
083    
084        /**
085         * Gets the index of the next element.
086         *
087         * @return the index of the next element in the iterator
088         */
089        public int nextIndex() {
090            return iterator.previousIndex();
091        }
092    
093        /**
094         * Checks whether there is a previous element.
095         *
096         * @return true if there is a previous element
097         */
098        public boolean hasPrevious() {
099            return iterator.hasNext();
100        }
101    
102        /**
103         * Gets the previous element.
104         * The next element is the previous in the list.
105         *
106         * @return the previous element in the iterator
107         */
108        public Object previous() {
109            Object obj = iterator.next();
110            validForUpdate = true;
111            return obj;
112        }
113    
114        /**
115         * Gets the index of the previous element.
116         *
117         * @return the index of the previous element in the iterator
118         */
119        public int previousIndex() {
120            return iterator.nextIndex();
121        }
122    
123        /**
124         * Removes the last returned element.
125         *
126         * @throws UnsupportedOperationException if the list is unmodifiable
127         * @throws IllegalStateException if there is no element to remove
128         */
129        public void remove() {
130            if (validForUpdate == false) {
131                throw new IllegalStateException("Cannot remove from list until next() or previous() called");
132            }
133            iterator.remove();
134        }
135    
136        /**
137         * Replaces the last returned element.
138         *
139         * @param obj  the object to set
140         * @throws UnsupportedOperationException if the list is unmodifiable
141         * @throws IllegalStateException if the iterator is not in a valid state for set
142         */
143        public void set(Object obj) {
144            if (validForUpdate == false) {
145                throw new IllegalStateException("Cannot set to list until next() or previous() called");
146            }
147            iterator.set(obj);
148        }
149    
150        /**
151         * Adds a new element to the list between the next and previous elements.
152         *
153         * @param obj  the object to add
154         * @throws UnsupportedOperationException if the list is unmodifiable
155         * @throws IllegalStateException if the iterator is not in a valid state for set
156         */
157        public void add(Object obj) {
158            // the validForUpdate flag is needed as the necessary previous()
159            // method call re-enables remove and add
160            if (validForUpdate == false) {
161                throw new IllegalStateException("Cannot add to list until next() or previous() called");
162            }
163            validForUpdate = false;
164            iterator.add(obj);
165            iterator.previous();
166        }
167    
168        /**
169         * Resets the iterator back to the start (which is the
170         * end of the list as this is a reversed iterator)
171         */
172        public void reset() {
173            iterator = list.listIterator(list.size());
174        }
175    
176    }