| Passage.java |
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 * Copyright: 2005-2013
18 * The copyright to this program is held by it's authors.
19 *
20 */
21 package org.crosswire.jsword.passage;
22
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.io.Writer;
26 import java.util.Iterator;
27
28 import org.crosswire.jsword.versification.Versification;
29
30 /**
31 * A Passage is a specialized Collection of Verses. The additions are:
32 * <ul>
33 * <li>List blurring
34 * <li>Range Counting and iteration (in addition to Verse counting etc)
35 * <li>List change notification, so you can register to update yourself, and
36 * this goes hand in hand with a added thread-safe contract.
37 * <li>getName() to be more VerseBase like.
38 * <li>Human readable serialization. So we can read and write to and from OLB
39 * style Passage files.
40 * </ul>
41 *
42 * <p>
43 * Passage no longer extends the Collection interface to avoid J2SE 1.1/1.2
44 * portability problems, and because many of the things that a Passage does rely
45 * on consecutive Verses which are an alien concept to Collections. So users
46 * would have to use the Passage interface anyway.
47 *
48 * <p>
49 * Other arguments for and against.
50 * <ul>
51 * <li>The generic version will postpone some type errors to runtime. Is this a
52 * huge problem? Are there many syntax errors that would be lost? Probably not.
53 * <li>The specific version would stop enhancements like add("Gen 1:1"); (But
54 * this is just syntactical sugar anyway).
55 * <li>The specific version allows functionality by is-a as well as has-a. But a
56 * Passage is fundamentally different so this is not that much use.
57 * <li>At the end of the day I expect people to use getName() instead of
58 * toString() and blur(), both of which are Passage things not Collection
59 * things. So the general use of these classes is via a Passage interface not a
60 * Collections one.
61 * <li>Note that the implementations of Passage could not adhere strictly to the
62 * Collections interface in returning false from add(), remove() etc, to specify
63 * if the Collection was changed. Given ranges and the like this can get very
64 * time consuming and complex.
65 * </ul>
66 *
67 * <p>
68 * The upshot of all this is that I am removing the Collections interface from
69 * Passage.
70 *
71 * <p>
72 * I considered giving Passages names to allow for a CLI that could use named
73 * RangedPassages, however that is perhaps better left to another class.
74 *
75 * @see gnu.lgpl.License for license details.<br>
76 * The copyright to this program is held by it's authors.
77 * @author Joe Walker [joe at eireneh dot com]
78 */
79 public interface Passage extends VerseKey {
80 /**
81 * Get the Versification that defines the Verses in the passage.
82 *
83 * @return this Passage's Versification.
84 */
85 Versification getVersification();
86
87 /**
88 * A summary of the verses in this Passage For example
89 * "10 verses in 4 books"
90 *
91 * @return a String containing an overview of the verses
92 */
93 String getOverview();
94
95 /**
96 * Returns the number of verses in this collection. Like Collection.size()
97 * This does not mean the Passage needs to use Verses, just that it
98 * understands the concept.
99 *
100 * @return the number of Verses in this collection
101 * @see Verse
102 */
103 int countVerses();
104
105 /**
106 * Determine whether there are two or more ranges.
107 *
108 * @param restrict
109 * Do we break ranges at chapter/book boundaries
110 * @return whether there are two or more ranges
111 * @see VerseRange
112 */
113 boolean hasRanges(RestrictionType restrict);
114
115 /**
116 * Like countVerses() that counts VerseRanges instead of Verses Returns the
117 * number of fragments in this collection. This does not mean the Passage
118 * needs to use VerseRanges, just that it understands the concept.
119 *
120 * @param restrict
121 * Do we break ranges at chapter/book boundaries
122 * @return the number of VerseRanges in this collection
123 * @see VerseRange
124 */
125 int countRanges(RestrictionType restrict);
126
127 /**
128 * Ensures that there are a maximum of <code>count</code> Verses in this
129 * Passage. If there were more than <code>count</code> Verses then a new
130 * Passage is created containing the Verses from <code>count</code>+1
131 * onwards. If there was not greater than <code>count</code> in the Passage,
132 * then the passage remains unchanged, and null is returned.
133 *
134 * @param count
135 * The maximum number of Verses to allow in this collection
136 * @return A new Passage containing the remaining verses or null
137 * @see Verse
138 */
139 Passage trimVerses(int count);
140
141 /**
142 * Ensures that there are a maximum of <code>count</code> VerseRanges in
143 * this Passage. If there were more than <code>count</code> VerseRanges then
144 * a new Passage is created containing the VerseRanges from
145 * <code>count</code>+1 onwards. If there was not greater than
146 * <code>count</code> in the Passage, then the passage remains unchanged,
147 * and null is returned.
148 *
149 * @param count
150 * The maximum number of VerseRanges to allow in this collection
151 * @param restrict
152 * Do we break ranges at chapter/book boundaries
153 * @return A new Passage containing the remaining verses or null
154 * @see VerseRange
155 */
156 Passage trimRanges(int count, RestrictionType restrict);
157
158 /**
159 * How many books are there in this Passage
160 *
161 * @return The number of distinct books
162 */
163 int booksInPassage();
164
165 /**
166 * Get a specific Verse from this collection
167 *
168 * @param offset
169 * The verse offset (legal values are 0 to countVerses()-1)
170 * @return The Verse
171 * @throws ArrayIndexOutOfBoundsException
172 * If the offset is out of range
173 */
174 Verse getVerseAt(int offset) throws ArrayIndexOutOfBoundsException;
175
176 /**
177 * Get a specific VerseRange from this collection
178 *
179 * @param offset
180 * The verse range offset (legal values are 0 to countRanges()-1)
181 * @param restrict
182 * Do we break ranges at chapter/book boundaries
183 * @return The Verse Range
184 * @throws ArrayIndexOutOfBoundsException
185 * If the offset is out of range
186 */
187 VerseRange getRangeAt(int offset, RestrictionType restrict) throws ArrayIndexOutOfBoundsException;
188
189 /**
190 * Like verseElements() that iterates over VerseRanges instead of Verses.
191 * Exactly the same data will be traversed, however using rangeIterator()
192 * will usually give less iterations (and never more)
193 *
194 * @param restrict
195 * Do we break ranges over chapters
196 * @return A list enumerator
197 */
198 Iterator<Key> rangeIterator(RestrictionType restrict);
199
200 /**
201 * Returns true if this collection contains all the specified Verse
202 *
203 * @param that
204 * Verse or VerseRange that may exist in this Passage
205 * @return true if this collection contains that
206 */
207 boolean contains(Key that);
208
209 /**
210 * Add this Verse/VerseRange to this Passage
211 *
212 * @param that
213 * The Verses to be removed from this Passage
214 */
215 void add(Key that);
216
217 /**
218 * Remove this Verse/VerseRange from this Passage
219 *
220 * @param that
221 * The Verses to be removed from this Passage
222 */
223 void remove(Key that);
224
225 /**
226 * Returns true if this Passage contains all of the verses in that Passage
227 *
228 * @param that
229 * Passage to be checked for containment in this collection.
230 * @return true if this reference contains all of the Verses in that Passage
231 */
232 boolean containsAll(Passage that);
233
234 /**
235 * To be compatible with humans we read/write ourselves to a file that a
236 * human can read and even edit. OLB verse.lst integration is a good goal
237 * here.
238 *
239 * @param in
240 * The stream to read from
241 * @exception java.io.IOException
242 * If the file/network etc breaks
243 * @exception NoSuchVerseException
244 * If the file was invalid
245 */
246 void readDescription(Reader in) throws IOException, NoSuchVerseException;
247
248 /**
249 * To be compatible with humans we read/write ourselves to a file that a
250 * human can read and even edit. OLB verse.lst integration is a good goal
251 * here.
252 *
253 * @param out
254 * The stream to write to
255 * @exception java.io.IOException
256 * If the file/network etc breaks
257 */
258 void writeDescription(Writer out) throws IOException;
259
260 /**
261 * For performance reasons we may well want to hint to the Passage that we
262 * have done editing it for now and that it is safe to cache certain values
263 * to speed up future reads. Any action taken by this method will be undone
264 * simply by making a future edit, and the only loss in calling
265 * optimizeReads() is a loss of time if you then persist in writing to the
266 * Passage.
267 */
268 void optimizeReads();
269
270 /**
271 * Event Listeners - Add Listener
272 *
273 * @param li
274 * The listener to add
275 */
276 void addPassageListener(PassageListener li);
277
278 /**
279 * Event Listeners - Remove Listener
280 *
281 * @param li
282 * The listener to remove
283 */
284 void removePassageListener(PassageListener li);
285 }
286