1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2005 - 2016
18   *
19   */
20  package org.crosswire.jsword.passage;
21  
22  import java.io.IOException;
23  import java.io.ObjectInputStream;
24  import java.util.Iterator;
25  
26  import org.crosswire.jsword.versification.Versification;
27  
28  /**
29   * A RocketPassage is a bit and heavy implementation of Passage that goes fairly
30   * quickly once let of the leash. It manages its speed by creating contained
31   * instances of DistinctPassage and RangedPassage and selects the fastest
32   * implementation for each of its methods from the 3 available.
33   * 
34   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
35   * @author Joe Walker
36   */
37  public class RocketPassage extends BitwisePassage {
38      /**
39       * Create a new RocketPassage
40       * 
41       * @param v11n
42       *            The Versification to which this Passage belongs.
43       */
44      public RocketPassage(Versification v11n) {
45          super(v11n);
46      }
47  
48      /**
49       * Create a Verse from a human readable string. The opposite of getName(),
50       * Given any RangedPassage v1, and the following
51       * <code>RangedPassage v2 = new RangedPassage(v1.getName());</code> Then
52       * <code>v1.equals(v2);</code> Theoretically, since there are many ways of
53       * representing a RangedPassage as text string comparison along the lines
54       * of: <code>v1.getName().equals(v2.getName())</code> could be false.
55       * However since getName() is standardized this will be true. We don't need
56       * to worry about thread safety in a ctor since we don't exist yet.
57       * 
58       * 
59       * @param v11n
60       *            The Versification to which this Passage belongs.
61       * @param refs
62       *            A String containing the text of the RangedPassage
63       * @param basis
64       *           The basis by which to interpret refs
65       * @throws NoSuchVerseException
66       *           if refs is invalid
67       */
68      protected RocketPassage(Versification v11n, String refs, Key basis) throws NoSuchVerseException {
69          super(v11n, refs, basis);
70      }
71  
72      /**
73       * Create a Verse from a human readable string. The opposite of getName(),
74       * Given any RangedPassage v1, and the following
75       * <code>RangedPassage v2 = new RangedPassage(v1.getName());</code> Then
76       * <code>v1.equals(v2);</code> Theoretically, since there are many ways of
77       * representing a RangedPassage as text string comparison along the lines
78       * of: <code>v1.getName().equals(v2.getName())</code> could be false.
79       * However since getName() is standardized this will be true. We don't need
80       * to worry about thread safety in a ctor since we don't exist yet.
81       * 
82       * 
83       * @param v11n
84       *            The Versification to which this Passage belongs.
85       * @param refs
86       *            A String containing the text of the RangedPassage
87       * @throws NoSuchVerseException
88       *            if refs is invalid
89       */
90      protected RocketPassage(Versification v11n, String refs) throws NoSuchVerseException {
91          this(v11n, refs, null);
92      }
93  
94      /*
95       * (non-Javadoc)
96       * 
97       * @see org.crosswire.jsword.passage.AbstractPassage#optimizeReads()
98       */
99      @Override
100     public void optimizeReads() {
101         raiseEventSuppresion();
102 
103         // We have to create the cached versions of these separately
104         // so that the calculations made by addAll(this) can
105         // safely call methods like countVerses() without any
106         // danger of them being optimized before the optimizations
107         // are ready for use.
108 
109         DistinctPassage dtemp = new DistinctPassage(getVersification());
110         dtemp.raiseEventSuppresion();
111         dtemp.addAll(this);
112         dtemp.lowerEventSuppressionAndTest();
113 
114         RangedPassage rtemp = new RangedPassage(getVersification());
115         rtemp.raiseEventSuppresion();
116         rtemp.addAll(this);
117         rtemp.lowerEventSuppressionAndTest();
118 
119         distinct = dtemp;
120         ranged = rtemp;
121 
122         // This is just an optimization so we dont need to fire any events
123         lowerEventSuppressionAndTest();
124     }
125 
126     /*
127      * (non-Javadoc)
128      * 
129      * @see org.crosswire.jsword.passage.AbstractPassage#optimizeWrites()
130      */
131     @Override
132     protected void optimizeWrites() {
133         distinct = null;
134         ranged = null;
135     }
136 
137     /*
138      * (non-Javadoc)
139      * 
140      * @see org.crosswire.jsword.passage.Passage#countRanges(int)
141      */
142     @Override
143     public int countRanges(RestrictionType restrict) {
144         if (ranged != null) {
145             return ranged.countRanges(restrict);
146         }
147 
148         return super.countRanges(restrict);
149     }
150 
151     /*
152      * (non-Javadoc)
153      * 
154      * @see org.crosswire.jsword.passage.Passage#countVerses()
155      */
156     @Override
157     public int countVerses() {
158         if (distinct != null) {
159             return distinct.countVerses();
160         }
161 
162         return super.countVerses();
163     }
164 
165     /*
166      * (non-Javadoc)
167      * 
168      * @see java.lang.Iterable#iterator()
169      */
170     @Override
171     public Iterator<Key> iterator() {
172         if (distinct != null) {
173             return distinct.iterator();
174         }
175 
176         return super.iterator();
177     }
178 
179     /*
180      * (non-Javadoc)
181      * 
182      * @see org.crosswire.jsword.passage.Passage#rangeIterator(int)
183      */
184     @Override
185     public Iterator<VerseRange> rangeIterator(RestrictionType restrict) {
186         if (ranged != null) {
187             return ranged.rangeIterator(restrict);
188         }
189 
190         return super.rangeIterator(restrict);
191     }
192 
193     /*
194      * (non-Javadoc)
195      * 
196      * @see org.crosswire.jsword.passage.Passage#isEmpty()
197      */
198     @Override
199     public boolean isEmpty() {
200         if (distinct != null) {
201             return distinct.isEmpty();
202         }
203 
204         return super.isEmpty();
205     }
206 
207     /*
208      * (non-Javadoc)
209      * 
210      * @see org.crosswire.jsword.passage.Passage#getVerseAt(int)
211      */
212     @Override
213     public Verse getVerseAt(int offset) throws ArrayIndexOutOfBoundsException {
214         if (distinct != null) {
215             return distinct.getVerseAt(offset);
216         }
217 
218         return super.getVerseAt(offset);
219     }
220 
221     /*
222      * (non-Javadoc)
223      * 
224      * @see org.crosswire.jsword.passage.Passage#getVerseRangeAt(int, int)
225      */
226     @Override
227     public VerseRange getRangeAt(int offset, RestrictionType restrict) throws ArrayIndexOutOfBoundsException {
228         if (ranged != null) {
229             return ranged.getRangeAt(offset, restrict);
230         }
231 
232         return super.getRangeAt(offset, restrict);
233     }
234 
235     /*
236      * (non-Javadoc)
237      * 
238      * @see org.crosswire.jsword.passage.Passage#booksInPassage()
239      */
240     @Override
241     public int booksInPassage() {
242         if (distinct != null) {
243             return distinct.booksInPassage();
244         }
245 
246         return super.booksInPassage();
247     }
248 
249     /*
250      * (non-Javadoc)
251      * 
252      * @see
253      * org.crosswire.jsword.passage.Passage#containsAll(org.crosswire.jsword
254      * .passage.Passage)
255      */
256     @Override
257     public boolean containsAll(Passage that) {
258         if (ranged != null) {
259             return ranged.containsAll(that);
260         }
261 
262         return super.containsAll(that);
263     }
264 
265     /**
266      * Serialization support
267      * 
268      * @param is
269      *            The stream to read our state from
270      * @throws IOException
271      *             if the read fails
272      * @throws ClassNotFoundException
273      *             If the read data is incorrect
274      */
275     private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
276         optimizeWrites();
277         is.defaultReadObject();
278     }
279 
280     /**
281      * The contained DistinctPassage
282      */
283     private transient DistinctPassage distinct;
284 
285     /**
286      * The contained RangedPassage
287      */
288     private transient RangedPassage ranged;
289 
290     /**
291      * Serialization ID
292      */
293     private static final long serialVersionUID = 3258125864771401268L;
294 }
295