001    /////////////////////////////////////////////////
002    //This file is part of Sears project.
003    //Subtitle Editor And Re-Synch
004    //A tool to easily modify and resynch movies subtitles.
005    /////////////////////////////////////////////////
006    //This program is free software; 
007    //you can redistribute it and/or modify it under the terms 
008    //of the GNU General Public License 
009    //as published by the Free Software Foundation; 
010    //either version 2 of the License, or (at your option) any later version.
011    /////////////////////////////////////////////////
012    //Sears project is available under sourceforge
013    //at adress: http://sourceforge.net/projects/sears/
014    //Copyright (C) 2005 Booba Skaya
015    //Mail: booba.skaya@gmail.com
016    /////////////////////////////////////////////////
017    
018    //some suggestions about this class: floriaen@gmail.com
019    
020    package sears.search.data;
021    
022    /**
023     * Manages <tt>ListOfRow</tt> structure with loop iteration
024     */
025    public class LoopIterator {
026    
027            private ListOfRow listOfRow;
028            private int index;
029    
030            /**
031             * Instantiate a new object
032             * @param aListOfRow    the list on which iterate
033             * @throws NullPointerException if <tt>aListOfRow</tt> is null
034             */
035            public LoopIterator(ListOfRow aListOfRow) {
036                    if( aListOfRow == null ) {
037                            throw new NullPointerException("cannot iterate on a null object");
038                    }
039                    listOfRow = aListOfRow;
040                    index = -1;
041            }
042    
043            /**
044             * <p>
045             * Gets the nearest element before means: 
046             * <br> gets the first smaller element before the element before the one given
047             * on parameters <br>if this element is not in the list, else it is return
048             * </p>
049             * <p>
050             * Method's algorithm uses is the <i>dichotomic</i> search
051             * </p>
052             * @param row   the element 
053             * @return              <tt>row</tt> if it is in the list or the first smaller element before it
054             * @throws              IllegalArgumentException if <tt>row</tt> is out of the bounds of the elements contained in the list
055             */
056            public int getTheNearestElementBefore(int row) {
057                    if( row < 0 ) {
058                            throw new IllegalArgumentException("negative value is not a valid value for a row");
059                    }
060                    // BEGIN
061                    int rowBefore = -1;
062                    if( !listOfRow.isEmpty() ) {
063                            int currentIndex = index;
064                            try {
065                                    int startAt = 0;
066                                    int stopAt = listOfRow.size() - 1;
067                                    int middle = 1;
068                                    boolean rowInTheList = false;
069                                    while( !rowInTheList && startAt <= stopAt ) {                        
070                                            middle = (startAt + stopAt)/2;
071                                            rowBefore = listOfRow.getRow(middle);
072                                            rowInTheList = ( rowBefore == row );
073                                            if( rowBefore > row ) {
074                                                    stopAt = middle - 1;
075                                            }
076                                            else if( rowBefore < row ) {
077                                                    startAt = middle + 1;
078                                            }
079                                    }
080                                    // moves current index:
081                                    index = middle;
082                                    if( !rowInTheList ) {
083                                            if( rowBefore > row ) {
084                                                    rowBefore = getPreviousElement();
085                                            }
086                                    }
087                                    // listOfRow exception:
088                            } catch( IndexOutOfBoundsException e ) {
089                                    // ensure the non modification of the state object,
090                                    // get back the iterator before the call of the method
091                                    // and return -1 which means that an error occurs
092                                    index = currentIndex;
093                                    rowBefore = -1;
094                            }
095                    }
096                    return rowBefore;
097            }
098    
099            // ensure that row is in the bounds
100            /**
101             * @param row   the row
102             * @return              the nearest element after
103             * @throws              IllegalArgumentException if <tt>row</tt> is out of the bounds of the elements contained in the list
104             */
105            public int getTheNearestElementAfter(int row) {
106                    if( row < 0 ) {
107                            throw new IllegalArgumentException("negative value is not a valid value for a row");
108                    }
109                    // BEGIN
110                    int rowAfter = -1;
111                    if( !listOfRow.isEmpty() ) {
112                            int currentIndex = index;
113                            try {
114                                    int startAt = 0;
115                                    int stopAt = listOfRow.size() - 1;
116                                    int middle = 0;
117                                    boolean rowInTheList = false;
118                                    while( !rowInTheList && startAt <= stopAt ) {                        
119                                            middle = (startAt + stopAt)/2;
120                                            rowAfter = listOfRow.getRow(middle);
121                                            rowInTheList = (rowAfter == row);
122                                            if( rowAfter > row ) {
123                                                    stopAt = middle - 1;
124                                            }
125                                            else if( rowAfter < row ) {
126                                                    startAt = middle + 1;
127                                            }
128                                    }
129                                    // moves current index:
130                                    index = middle;
131                                    if( !rowInTheList ) {
132                                            if( rowAfter < row ) {
133                                                    rowAfter = getNextElement();
134                                            }
135                                    }                       
136    
137                                    // listOfRow exception:
138                            } catch( IndexOutOfBoundsException e ) {
139                                    // ensure the non modification of the state object,
140                                    // get back the iterator before the call of the method
141                                    // and return -1 which means that an error occurs
142                                    index = currentIndex;
143                                    rowAfter = -1;
144                            }
145                    }
146                    return rowAfter;
147            }
148    
149    //      NEXT ROW METHOD
150    
151    
152            /**
153             * Returns the next positive element of the list
154             * @return      the next element in the list, if the list is empty -1 is return
155             */
156            public int getNextElement() {
157                    return getNextElement(index);
158            }
159    
160            /**
161             * returns the next element at index given in parameters
162             */
163            private int getNextElement(int startIndex) {
164                    index = startIndex;
165                    int row = -1;
166                    if( !listOfRow.isEmpty() ) {
167                            row = listOfRow.getRow(getNextIndex());
168                    }
169                    return row;
170            }
171    
172    //      PREVIOUS ROW METHODS
173    
174    
175            /**
176             * Returns the previous positive element of the list
177             * @return      the previous element in the list, if the list is empty -1 is return
178             */
179            public int getPreviousElement() {
180                    return getPreviousElement(index);
181            }
182    
183            private int getPreviousElement(int startIndex) {
184                    index = startIndex;
185                    int row = -1;
186                    if( !listOfRow.isEmpty() ) {
187                            row = listOfRow.getRow(getPreviousIndex());
188                    }
189                    return row;
190            }
191    
192    //      INDEX MANIPULATIONS
193    //      ensure that the loop iteration is respected
194    //      access to the index variable must be done with this methods
195    
196            /**
197             * Gets the next index, ensures that the loop iteration is done.
198             * <br> Increments the current <tt>index</tt>
199             * @return the incremented current index
200             */
201            private int getNextIndex() {
202                    if( index + 1 >= listOfRow.size() ) {
203                            index = -1;
204                    }
205                    index++;
206                    return index;
207            }
208    
209            /**
210             * Gets the previous index, ensures that the loop iteration is done.
211             * <br> Decrements the current <tt>index</tt>
212             * @return the decremented current index
213             */
214            private int getPreviousIndex() {
215                    if( index - 1 < 0 ) {
216                            index = listOfRow.size();
217                    }
218                    index--;
219                    return index;
220            }
221    
222            //
223            //      "SAFE" METHODS
224            //      do not change iteration state
225    
226            /**
227             * SAFE METHOD, do not change iteration state
228             * @return the current element
229             */
230            public int getCurrentElement() {
231                    return listOfRow.getRow(index);
232            }       
233    
234            /**
235             * SAFE METHOD, do not change iteration state
236             * @return the first element of the list
237             */
238            public int getFirstElement() {
239                    return listOfRow.getRow(0);
240            }
241    
242            /**
243             * SAFE METHOD, do not change iteration state
244             * @return the last element of the list
245             */
246            public int getLastElement() {
247                    return listOfRow.getRow(listOfRow.size() - 1);
248            }
249    
250            /**
251             * SAFE METHOD, do not change iteration state
252             * @return the index of the current element in the list
253             */
254            public int getIndexOfTheCurrentElement() {
255                    return index;
256            }
257    }