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    import java.util.ArrayList;
023    
024    import sears.file.Subtitle;
025    
026    /**
027     * Data structure to manage result of a search.
028     * <br><tt>CharIndexIterator</tt> performs a loop iteration
029     *
030     */
031    public class CharIndexIterator {
032            
033            private Window window;
034            private LoopIterator loopIterator;
035            private SubtitleFile subtitleFile;
036    
037            ArrayList<Subtitle> subtitleList;
038            private String textForTheSearch;
039    
040            /**
041             * Constructs a new <tt>CharIndexIterator</tt> object
042             * @param subtitleList  the subtitle list
043             * @param str                   the searched string 
044             * @throws IllegalArgumentException if one of the arguments id <tt>null</tt>
045             */
046            public CharIndexIterator(ArrayList<Subtitle> subtitleList, String str) {
047                    if( subtitleList == null || subtitleList.isEmpty() ) {
048                            throw new IllegalArgumentException("the list of subtitles is null or empty");
049                    }
050                    
051                    window = new Window();
052                    this.subtitleList = subtitleList;
053                    subtitleFile = new SubtitleFile(subtitleList);
054                    setANewTextForTheSearch(str);
055            }
056    
057            /**
058             * Sets a new array of <tt>Subtitle</tT> object
059             * @param newSubtitleList       the new array
060             */
061            public void setANewSubtitleList(ArrayList<Subtitle> newSubtitleList) {
062                    subtitleFile = new SubtitleFile(newSubtitleList);
063                    loopIterator = subtitleFile.getAllRowWhichContainsAtLeastOneOccurrenceOfText(textForTheSearch).iterator();
064                    window = new Window();
065            }
066    
067            /**
068             * Set if needed a new text for the search
069             * @param str           the new text
070             * @return                      true if the set is needed, false if not
071             */
072            public boolean setANewTextForTheSearch(String str) {
073                    if( !isAValidText(str) ) {
074                            throw new IllegalArgumentException("the string is not valid");
075                    }
076                    str = isTextChanged(str);
077                    if( str != null) {
078                            setTextForTheSearch(str);
079                    }
080                    return (str != null);
081            }
082    
083            private void setTextForTheSearch(String newText) {
084                    if( !isAValidText(newText) ) {
085                            throw new IllegalArgumentException("the string entered is not a valid string");
086                    }
087                    textForTheSearch = newText;
088                    fireTextChanged();
089            }
090    
091            //private void resetWindow
092    
093            private void fireTextChanged() {
094                    loopIterator = subtitleFile.getAllRowWhichContainsAtLeastOneOccurrenceOfText(textForTheSearch).iterator();
095                    window = window.getEmptyClonedWindow();
096            }
097    
098            /**
099             * Tests the <code>String</code> object given in parameter.
100             * @param textToTest the <code>String</code> object to test
101             * @return <code>textToTest</code> to lower case if it is different that the text stored, <code>null</code> if not
102             */
103            private String isTextChanged(String textToTest) {
104                    textToTest = textToTest.toLowerCase();
105                    if( textForTheSearch != null && textForTheSearch.contentEquals(textToTest) ) {
106                            textToTest = null;
107                    }               
108                    return textToTest;
109            }
110    
111            private boolean isAValidText(String text) {
112                    return ( text != null && text.trim().length() > 0 );
113            }
114    
115            // ACCESS METHODS
116            //
117    
118            /**
119             * Initializes and returns an array of two int
120             * <br>if <tt>row</tt> or <tt>index</tt> are negative, null is returned
121             * @param row   the row
122             * @param index a char index
123             * @return              an array of two int or null     
124             */
125            private int[] rowAndCharIndex(int row, int index) {
126                    int[] rowAndCharIndex = new int[2];
127                    if( row < 0 || index < 0 ) {
128                            rowAndCharIndex = null;
129                    } else {
130                            rowAndCharIndex[0] = row;
131                            rowAndCharIndex[1] = index;
132                    }
133                    return rowAndCharIndex;
134            }
135    
136            /**
137             * Returns the subtitle text at the index given in parameters
138             * @param index the index in the list
139             * @return              a string or null if <tt>index</tt> is out of list bounds
140             */
141            private String getSubtitleAtIndex(int index) {
142                    String subtitle = null;
143                    // ensure coherence with the subtitleList
144                    if( index >= 0 && index < subtitleList.size() ) {
145                            subtitle = subtitleList.get(index).getSubtitle();
146                    }
147                    return subtitle;
148            }
149    
150            /**
151             * Gets the next row and char index
152             * <br> INCOHERENCE: row < 0 or row > last row...
153             * @return an array of two positive int or null if an incoherence appears during the method
154             * 
155             */
156            public int[] getNextRowAndCharIndex() {
157                    int charIndex = window.getNextCharIndex();
158                    if( charIndex == -1 ) {
159                            int row = loopIterator.getNextElement();
160                            if( row != -1 ) {                               
161                                    String subtitle = getSubtitleAtIndex(row);
162                                    // test the coherence
163                                    if( subtitle != null ) {
164                                            // update window:
165                                            window.setWindowForGettingNextElement(subtitle, textForTheSearch);
166                                            charIndex = window.getNextCharIndex();
167                                            // test the coherence of the result:
168                                            if( charIndex >= (subtitle.length() - textForTheSearch.length()) ) {
169                                                    // negative charIndex cause that the #rowAndCharMethod(int,int) method
170                                                    // returns null
171                                                    charIndex = -1;
172                                            }
173                                    } else {
174                                            charIndex = -1;
175                                    }
176                            }
177                    }
178                    return rowAndCharIndex(loopIterator.getCurrentElement(), charIndex);
179            }
180    
181            /**
182             * Gets the row and first char index of the previous occurrence
183             * @return      an array of two <tt>int</tt>, the row and the first char index of the searched text
184             *                      null if there's no previous occurrence (this means that there's no occurrence at all
185             */
186            public int[] getPreviousRowAndCharIndex() {
187                    int charIndex = window.getPreviousCharIndex();
188                    if( charIndex == -1 ) {
189                            int row = loopIterator.getPreviousElement();
190                            if( row != -1 ) {                               
191                                    String subtitle = getSubtitleAtIndex(row);
192                                    // test the coherence
193                                    if( subtitle != null ) {
194                                            // update window:
195                                            window.setWindowForGettingPreviousElement(subtitle, textForTheSearch);
196                                            charIndex = window.getPreviousCharIndex();
197                                            // test the coherence of the result:
198                                            if( charIndex >= (subtitle.length() - textForTheSearch.length()) ) {
199                                                    // negative charIndex cause that the #rowAndCharMethod(int,int) method
200                                                    // returns null
201                                                    charIndex = -1;
202                                            }
203                                    } else {
204                                            charIndex = -1;
205                                    }
206                            }
207                    }
208                    return rowAndCharIndex(loopIterator.getCurrentElement(), charIndex);
209            }
210    
211            /**
212             * Gets the row and first char index of the next occurrence after <tt>row</tt>
213             * @param row the row
214             * @return      an array of two <tt>int</tt>, the row and the first char index of the searched text
215             */
216            public int[] getNextRowAndCharIndexBeginAtRow(int row) {
217                    int charIndex = -1;
218                    if( row >= 0 && row < subtitleList.size() ) {
219                            row = loopIterator.getTheNearestElementAfter(row);
220                            String subtitle = getSubtitleAtIndex(row);
221                            // ensures that row is valid compared to the subtitle list
222                            // row for table/index for subtitleList (same thing)
223                            if( subtitle != null ) {
224                                    window.setWindowForGettingNextElement(subtitle, textForTheSearch);
225                                    charIndex = window.getNextCharIndex();
226                                    // test the coherence of the result:
227                                    if( charIndex >= (subtitle.length() - textForTheSearch.length()) ) {
228                                            // negative charIndex cause that the #rowAndCharMethod(int,int) method
229                                            // returns null
230                                            charIndex = -1;
231                                    }
232                            }// else charIndex remain equals to -1, return value will be null 
233                    }
234                    return rowAndCharIndex(row, charIndex);
235            }
236    
237            /**
238             * Gets the row and first char index of the previous occurrence after <tt>row</tt>
239             * @param row the row
240             * @return      an array of two <tt>int</tt>, the row and the first char index of the searched text
241             */
242            public int[] getPreviousRowAndCharIndexBeginAtRow(int row) {
243                    int charIndex = -1;
244                    if( row >= 0 && row < subtitleList.size() ) {
245                            row = loopIterator.getTheNearestElementBefore(row);
246                            String subtitle = getSubtitleAtIndex(row);
247                            // ensures that row is valid compared to the subtitle list
248                            // row for table/index for subtitleList (same thing)
249                            if( subtitle != null ) {
250                                    window.setWindowForGettingPreviousElement(subtitle, textForTheSearch);
251                                    charIndex = window.getPreviousCharIndex();
252                                    // test the coherence of the result:
253                                    if( charIndex >= (subtitle.length() - textForTheSearch.length()) ) {
254                                            // negative charIndex cause that the #rowAndCharMethod(int,int) method
255                                            // returns null
256                                            charIndex = -1;
257                                    }
258                            }// else charIndex remain equals to -1, return value will be null 
259                    }
260                    return rowAndCharIndex(row, charIndex);
261            }
262    }