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