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