Source code: com/eireneh/bible/passage/Books.java
1
2 package com.eireneh.bible.passage;
3
4 import java.util.*;
5
6 import com.eireneh.util.*;
7 import com.eireneh.util.LogicError;
8
9 /**
10 * Books is a static class that deals with Book number conversions and similar.
11 * We start counting at 1 for books, chapters and verses (so Genesis=1, Revelation=66).
12 * However internally books start counting at 0 and go up to 65.
13 * <p>I've considered merging Books and PassageUtil since they are both supporting
14 * static only classes. However they are both non-trivial, so together they would
15 * be large, and there is a good dividing line between the 2.
16 *
17 * <table border='1' cellPadding='3' cellSpacing='0' width="100%">
18 * <tr><td bgColor='white'class='TableRowColor'><font size='-7'>
19 * Distribution Licence:<br />
20 * Project B is free software; you can redistribute it
21 * and/or modify it under the terms of the GNU General Public License,
22 * version 2 as published by the Free Software Foundation.<br />
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.<br />
27 * The License is available on the internet
28 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, by writing to
29 * <i>Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 * MA 02111-1307, USA</i>, Or locally at the Licence link below.<br />
31 * The copyright to this program is held by it's authors.
32 * </font></td></tr></table>
33 * @see <a href='http://www.eireneh.com/servlets/Web'>Project B Home</a>
34 * @see docs.Licence
35 * @author Joe Walker
36 * @version D9.I9.T7
37 * @stereotype utility
38 */
39 public class Books implements PassageConstants
40 {
41 /**
42 * Ensure that we can not be instansiated
43 */
44 private Books()
45 {
46 }
47
48 /**
49 * How do we report the names of the books?.
50 * These are static. This is on the assumption that we will not want to have
51 * different sections of the app using a different format. I expect this to
52 * be a good assumption, and it saves passing a Book class around everywhere.
53 * Books.MIXED is not allowed
54 * @param book_case The new case to use for reporting book names
55 * @exception IllegalArgumentException If the case is not between 0 and 2
56 * @see Passage
57 * @see #getCase
58 */
59 public final static void setCase(int book_case)
60 {
61 if (book_case < 0 || book_case > 2)
62 {
63 Object[] params = new Object[] { new Integer(book_case) };
64 throw new IllegalArgumentException(PassageUtil.getResource("books_error_case", params));
65 }
66
67 Books.book_case = book_case;
68 }
69
70 /**
71 * How do we report the names of the books?.
72 * @return The current case setting
73 * @see Passage
74 * @see #setCase
75 */
76 public final static int getCase()
77 {
78 return Books.book_case;
79 }
80
81 /**
82 * Get the full name of a book (e.g. "Genesis").
83 * Altered by the case setting (see setBookCase())
84 * @param idx The book number (1-66)
85 * @return The full name of the book
86 * @exception NoSuchVerseException If the book number is not valid
87 */
88 public final static String getLongBookName(int book) throws NoSuchVerseException
89 {
90 try
91 {
92 switch (book_case)
93 {
94 case CASE_LOWER:
95 return full_books_lower[book-1];
96 case CASE_UPPER:
97 return full_books_upper[book-1];
98 default:
99 return full_books[book-1];
100 }
101 }
102 catch (ArrayIndexOutOfBoundsException ex)
103 {
104 // This is faster than doing the check explicitly, unless
105 // The exception is actually thrown, then it is a lot slower
106 // I'd like to think that the norm is to get it right
107 throw new NoSuchVerseException("passg_books_book",
108 new Object[] { new Integer(book) });
109 }
110 }
111
112 /**
113 * Get the short name of a book (e.g. "Gen").
114 * Altered by the case setting (see setBookCase())
115 * @param idx The book number (1-66)
116 * @return The short name of the book
117 * @exception NoSuchVerseException If the book number is not valid
118 */
119 public final static String getShortBookName(int book) throws NoSuchVerseException
120 {
121 try
122 {
123 switch (book_case)
124 {
125 case CASE_LOWER:
126 return short_books_lower[book-1];
127 case CASE_UPPER:
128 return short_books_upper[book-1];
129 default:
130 return short_books[book-1];
131 }
132 }
133 catch (ArrayIndexOutOfBoundsException ex)
134 {
135 // This is faster than doing the check explicitly, unless
136 // The exception is actually thrown, then it is a lot slower
137 // I'd like to think that the norm is to get it right
138 throw new NoSuchVerseException("passg_books_book",
139 new Object[] { new Integer(book) });
140 }
141 }
142
143 /**
144 * Get the memory jogger letters for a book.
145 * @param idx The book number (1-66)
146 * @return A 2 character string containing the memory jogger characters
147 * @exception NoSuchVerseException If the book number is not valid
148 */
149 public final static String getBookJogger(int book) throws NoSuchVerseException
150 {
151 try
152 {
153 return jog_books[book-1];
154 }
155 catch (ArrayIndexOutOfBoundsException ex)
156 {
157 // This is faster than doing the check explicitly, unless
158 // The exception is actually thrown, then it is a lot slower
159 // I'd like to think that the norm is to get it right
160 throw new NoSuchVerseException("passg_books_book",
161 new Object[] { new Integer(book) });
162 }
163 }
164
165 /**
166 * Get the Short name of a book
167 * @param idx The book number (1-66)
168 * @return A string containing the memory jogger characters
169 * @exception IllegalArgumentException If the number is negative
170 */
171 public final static String getNumberJogger(long number)
172 {
173 if (number < 0)
174 {
175 Object[] params = new Object[] { new Long(number) };
176 throw new IllegalArgumentException(PassageUtil.getResource("books_error_jogger", params));
177 }
178
179 String num = ""+number;
180 String retcode = "";
181
182 for (int i=0; i<num.length(); i++)
183 {
184 retcode = retcode + jog_numbers[Character.getNumericValue(num.charAt(i))];
185 }
186
187 return retcode;
188 }
189
190 /**
191 * Get number of a book from its name.
192 * @param find The string to identify
193 * @return The book number (1 to 66)
194 * @exception NoSuchVerseException If the text can not be matched
195 */
196 public final static int getBookNumber(String find) throws NoSuchVerseException
197 {
198 String match = find.toLowerCase();
199
200 // Check this isn't a number.
201 // And that it does not start with any of the numeric book markers
202 if (!PassageUtil.containsLetter(find))
203 {
204 boolean numeric_book = false;
205 for (int i=0; i<VERSE_NUMERIC_BOOK.length; i++)
206 {
207 if (find.startsWith(VERSE_NUMERIC_BOOK[i]))
208 numeric_book = true;
209 }
210
211 if (!numeric_book)
212 throw new NoSuchVerseException("passg_books_number", new Object[] { find });
213 }
214
215 // Does it match a long version of the book
216 // or a short version
217 for (int i=0; i<full_books.length; i++)
218 {
219 if (full_books_lower[i].startsWith(match)) return i+1;
220 if (match.startsWith(short_books_lower[i])) return i+1;
221 }
222
223 // The alternative versions
224 for (int i=0; i<alt_books.length; i++)
225 {
226 for (int j=0; j<alt_books[i].length; j++)
227 {
228 if (match.startsWith(alt_books_lower[i][j])) return i+1;
229 }
230 }
231
232 // if we start with a book number id mark
233 for (int i=0; i<VERSE_NUMERIC_BOOK.length; i++)
234 {
235 if (find.startsWith(VERSE_NUMERIC_BOOK[i]))
236 {
237 int book = Integer.parseInt(find.substring(VERSE_NUMERIC_BOOK[i].length()));
238 if (book < 1 || book > 66)
239 {
240 throw new NoSuchVerseException("passg_books_book",
241 new Object[] { new Integer(book) });
242 }
243 return book;
244 }
245 }
246
247 throw new NoSuchVerseException("passg_books_find",
248 new Object[] { find });
249 }
250
251 /**
252 * Is the given string a valid book name. If this method returns true then
253 * getBookNumber() will return a number and not throw an exception.
254 * @param find The string to identify
255 * @return The book number (1 to 66)
256 * @exception NoSuchVerseException If the text can not be matched
257 */
258 public final static boolean isBookName(String find) throws NoSuchVerseException
259 {
260 String match = find.toLowerCase();
261
262 if (!PassageUtil.containsLetter(find)) return false;
263
264 // This could be sped up with less of the toLowerCase()
265 for (int i=0; i<full_books.length; i++)
266 {
267 if (full_books_lower[i].startsWith(match)) return true;
268 if (match.startsWith(short_books_lower[i])) return true;
269
270 for (int j=0; j<alt_books[i].length; j++)
271 {
272 if (match.startsWith(alt_books_lower[i][j])) return true;
273 }
274 }
275
276 return false;
277 }
278
279 /**
280 * Count the books in the Bible.
281 * @return 66 always - the number of books in the Bible
282 */
283 public final static int booksInBible()
284 {
285 return books_in_bible;
286 }
287
288 /**
289 * Count the chapters in the Bible.
290 * @return 1189 always - the number of chapters in the Bible
291 */
292 public final static int chaptersInBible()
293 {
294 return chapters_in_bible;
295 }
296
297 /**
298 * Count the verses in the Bible.
299 * This counts possible verses, so this number is not affected
300 * by some versions missing out some verses as 'there in error'
301 * @return 31102 always - the number of verses in the Bible
302 */
303 public final static int versesInBible()
304 {
305 return verses_in_bible;
306 }
307
308 /**
309 * Count the chapters in this book.
310 * @param book The book part of the reference.
311 * @return The number of chapters
312 * @exception NoSuchVerseException If the book number is not valid
313 */
314 public final static int chaptersInBook(int book) throws NoSuchVerseException
315 {
316 try
317 {
318 return chapters_in_book[book-1];
319 }
320 catch (ArrayIndexOutOfBoundsException ex)
321 {
322 // This is faster than doing the check explicitly, unless
323 // The exception is actually thrown, then it is a lot slower
324 // I'd like to think that the norm is to get it right
325 throw new NoSuchVerseException("passg_books_book",
326 new Object[] { new Integer(book) });
327 }
328 }
329
330 /**
331 * Count the verses in a chapter.
332 * @param book The book part of the reference.
333 * @param chapter The current chapter
334 * @return The number of verses
335 * @exception NoSuchVerseException If the book or chapter number is not valid
336 */
337 public final static int versesInChapter(int book, int chapter) throws NoSuchVerseException
338 {
339 try
340 {
341 return verses_in_chapter[book-1][chapter-1];
342 }
343 catch (ArrayIndexOutOfBoundsException ex)
344 {
345 // This is faster than doing the check explicitly, unless
346 // The exception is actually thrown, then it is a lot slower
347 // I'd like to think that the norm is to get it right
348
349 Object[] params = new Object[] { new Integer(book), new Integer(chapter) };
350 throw new NoSuchVerseException("passg_books_bookchap", params);
351 }
352 }
353
354 /**
355 * Count the verses in a book.
356 * @param book The book part of the reference.
357 * @return The number of verses
358 * @exception NoSuchVerseException If the book number is not valid
359 */
360 public final static int versesInBook(int book) throws NoSuchVerseException
361 {
362 try
363 {
364 return verses_in_book[book-1];
365 }
366 catch (ArrayIndexOutOfBoundsException ex)
367 {
368 // This is faster than doing the check explicitly, unless
369 // The exception is actually thrown, then it is a lot slower
370 // I'd like to think that the norm is to get it right
371 throw new NoSuchVerseException("passg_books_book",
372 new Object[] { new Integer(book) });
373 }
374 }
375
376 /**
377 * Where does this verse come in the Bible. Starting with Gen 1:1 as
378 * number 1 counting up one per verse and not resetting at each new
379 * chapter.
380 * @param book The book part of the reference.
381 * @param chapter The current chapter
382 * @param verse The current verse
383 * @return The ordinal number of verses
384 * @exception NoSuchVerseException If the reference is illegal
385 */
386 public final static int verseOrdinal(int book, int chapter, int verse) throws NoSuchVerseException
387 {
388 validate(book, chapter, verse);
389 return ordinal_at_start_of_chapter[book-1][chapter-1] + verse - 1;
390 }
391
392 /**
393 * Where does this verse come in the Bible. Starting with Gen 1:1 as
394 * number 1 counting up one per verse and not resetting at each new
395 * chapter.
396 * @param ref An array of 3 ints, book, chapter, verse
397 * @return The ordinal number of the verse
398 * @exception com.eireneh.bible.passage.NoSuchVerseException If the reference is illegal
399 */
400 public final static int verseOrdinal(int[] ref) throws NoSuchVerseException
401 {
402 if (ref.length != 3)
403 throw new NoSuchVerseException("passg_books_ordinal");
404
405 return verseOrdinal(ref[0], ref[1], ref[2]);
406 }
407
408 /**
409 * Where does this verse come in the Bible. Starting with Gen 1:1 as
410 * number 1 counting up one per verse and not resetting at each new
411 * chapter.
412 * @param ordinal The ordinal number of the verse
413 * @return An array of 3 ints, book, chapter, verse
414 * @exception NoSuchVerseException If the reference is illegal
415 */
416 public final static int[] decodeOrdinal(int ordinal) throws NoSuchVerseException
417 {
418 if (ordinal < 1 || ordinal > Books.versesInBible())
419 {
420 Object[] params = new Object[] { new Integer(Books.versesInBible()), new Integer(ordinal) };
421 throw new NoSuchVerseException("passg_books_decode", params);
422 }
423
424 for (int b=books_in_bible; b>0; b--)
425 {
426 if (ordinal >= ordinal_at_start_of_book[b-1])
427 {
428 int cib = Books.chaptersInBook(b);
429 for (int c=cib; c>0; c--)
430 {
431 if (ordinal >= ordinal_at_start_of_chapter[b-1][c-1])
432 {
433 return new int[] { b, c, ordinal - ordinal_at_start_of_chapter[b-1][c-1] + 1 };
434 }
435 }
436 }
437 }
438
439 throw new LogicError();
440 }
441
442 /**
443 * Does the following represent a real verse? It is code like this
444 * that makes me wonder if I18 is done well/worth doing. All this
445 * code does is check if the numbers are valid, but the exception
446 * handling code is huge :(
447 * @param book The book part of the reference.
448 * @param chapter The chapter part of the reference.
449 * @param verse The verse part of the reference.
450 * @exception NoSuchVerseException If the reference is illegal
451 */
452 public final static void validate(int book, int chapter, int verse) throws NoSuchVerseException
453 {
454 // Check the book
455 if (book < 1 || book > books_in_bible)
456 {
457 throw new NoSuchVerseException("passg_books_book",
458 new Object[] { new Integer(book) });
459 }
460
461 // Check the chapter
462 if (chapter < 1 || chapter > chaptersInBook(book))
463 {
464 Object[] params = new Object[]
465 {
466 new Integer(chaptersInBook(book)),
467 full_books[book-1], new Integer(chapter),
468 };
469 throw new NoSuchVerseException("passg_books_chapter", params);
470 }
471
472 // Check the verse
473 if (verse < 1 || verse > versesInChapter(book, chapter))
474 {
475 Object[] params = new Object[]
476 {
477 new Integer(versesInChapter(book, chapter)),
478 full_books[book-1],
479 new Integer(chapter),
480 new Integer(verse),
481 };
482 throw new NoSuchVerseException("passg_books_verse", params);
483 }
484 }
485
486 /**
487 * Does the following represent a real verse?
488 * @param ref An array of 3 ints, book, chapter, verse
489 * @exception NoSuchVerseException If the reference is illegal
490 */
491 public final static void validate(int[] ref) throws NoSuchVerseException
492 {
493 if (ref.length != 3)
494 throw new NoSuchVerseException("passg_books_ordinal");
495
496 validate(ref[BOOK], ref[CHAPTER], ref[VERSE]);
497 }
498
499 /**
500 * Fix up these verses so that they are as valid a possible. This is currently
501 * done so that we can say "Gen 1:1" + 31 = "Gen 1:32" and "Gen 1:32".patch()
502 * is "Gen 2:1".
503 * <p>There is another patch system that allows us to use large numbers to
504 * mean "the end of" so "Gen 1:32".otherPatch() gives "Gen 1:31". This could
505 * be useful to allow the user to enter things like "Gen 1:99" meaning
506 * the end of the chapter. Or "Isa 99:1" to mean the last chapter in Isaiah
507 * verse 1 or even "Rev 99:99" to mean the last verse in the Bible.
508 * <p>However I have not implemented this because I've used a different convention:
509 * "Gen 1:$" (OLB compatible) or "Gen 1:ff" (common comentary usage) to
510 * mean the end of the chapter - So the functionality is there anyway.
511 * <p>I think that getting into the habit of typing "Gen 1:99" is bad. It could
512 * be the source of surprises "Psa 119:99" is not what you'd might expect,
513 * and neither is "Psa 99:1" is you wanted the last chapter in Psalms - expecting
514 * us to type "Psa 999:1" seems like we're getting silly.
515 * <p>However dispite this maybe we should provide the functionality anyway.
516 * @param ref An array of 3 ints, book, chapter, verse. This array will be changed.
517 * @return The original array that has been patched.
518 */
519 public final static int[] patch(int[] ref)
520 {
521 try
522 {
523 // If they are too small
524 if (ref[BOOK] <= 0) ref[BOOK] = 1;
525 if (ref[CHAPTER] <= 0) ref[CHAPTER] = 1;
526 if (ref[VERSE] <= 0) ref[VERSE] = 1;
527
528 // If they are too big
529 if (ref[BOOK] > books_in_bible)
530 {
531 ref[BOOK] = Names.Revelation;
532 ref[CHAPTER] = chaptersInBook(ref[BOOK]);
533 ref[VERSE] = versesInChapter(ref[BOOK], ref[CHAPTER]);
534 return ref;
535 }
536
537 while (ref[CHAPTER] > chaptersInBook(ref[BOOK]))
538 {
539 ref[CHAPTER] -= chaptersInBook(ref[BOOK]);
540 ref[BOOK] += 1;
541
542 if (ref[BOOK] > books_in_bible)
543 {
544 ref[BOOK] = Names.Revelation;
545 ref[CHAPTER] = chaptersInBook(ref[BOOK]);
546 ref[VERSE] = versesInChapter(ref[BOOK], ref[CHAPTER]);
547 return ref;
548 }
549 }
550
551 while (ref[VERSE] > versesInChapter(ref[BOOK], ref[CHAPTER]))
552 {
553 ref[VERSE] -= versesInChapter(ref[BOOK], ref[CHAPTER]);
554 ref[CHAPTER] += 1;
555
556 if (ref[CHAPTER] > chaptersInBook(ref[BOOK]))
557 {
558 ref[CHAPTER] -= chaptersInBook(ref[BOOK]);
559 ref[BOOK] += 1;
560
561 if (ref[BOOK] > books_in_bible)
562 {
563 ref[BOOK] = Names.Revelation;
564 ref[CHAPTER] = chaptersInBook(ref[BOOK]);
565 ref[VERSE] = versesInChapter(ref[BOOK], ref[CHAPTER]);
566 return ref;
567 }
568 }
569 }
570
571 return ref;
572 }
573 catch (Exception ex)
574 {
575 throw new LogicError(ex);
576 }
577 }
578
579 /**
580 * How many verses between ref1 and ref2 (inclusive).
581 * @param book1 The book part of the first reference.
582 * @param chapter1 The chapter part of the first reference.
583 * @param verse1 The verse part of the first reference.
584 * @param book2 The book part of the second reference.
585 * @param chapter2 The chapter part of the second reference.
586 * @param verse2 The verse part of the second reference.
587 * @exception NoSuchVerseException If either reference is illegal
588 */
589 public final static int verseCount(int book1, int chapter1, int verse1, int book2, int chapter2, int verse2) throws NoSuchVerseException
590 {
591 int verse_ord1 = verseOrdinal(book1, chapter1, verse1);
592 int verse_ord2 = verseOrdinal(book2, chapter2, verse2);
593
594 return verse_ord2 - verse_ord1 + 1;
595 }
596
597 /**
598 * How many verses between ref1 and ref2 (inclusive).
599 * @param ref1 An array of 3 ints, book, chapter, verse for the first reference.
600 * @param ref2 An array of 3 ints, book, chapter, verse for the second reference.
601 * @exception NoSuchVerseException If either reference is illegal
602 */
603 public final static int verseCount(int[] ref1, int[] ref2) throws NoSuchVerseException
604 {
605 if (ref1.length != 3 || ref2.length != 3)
606 throw new NoSuchVerseException("books_error_ordinal");
607
608 return verseCount(ref1[0], ref1[1], ref1[2], ref2[0], ref2[1], ref2[2]);
609 }
610
611 /**
612 * Is this book part of the Pentateuch?
613 * @param book The book to test
614 * @return True if this book is a part of this section
615 */
616 public final static boolean isPentateuch(int book)
617 {
618 return book >= Names.Genesis && book <= Names.Deuteronomy;
619 }
620
621 /**
622 * Is this book part of the OT History?
623 * @param book The book to test
624 * @return True if this book is a part of this section
625 */
626 public final static boolean isHistory(int book)
627 {
628 return book >= Names.Joshua && book <= Names.Esther;
629 }
630
631 /**
632 * Is this book part of the OT History?
633 * @param book The book to test
634 * @return True if this book is a part of this section
635 */
636 public final static boolean isPoetry(int book)
637 {
638 return book >= Names.Job && book <= Names.SongOfSolomon;
639 }
640
641 /**
642 * Is this book part of the major prophets?
643 * @param book The book to test
644 * @return True if this book is a part of this section
645 */
646 public final static boolean isMajorProphet(int book)
647 {
648 return book >= Names.Isaiah && book <= Names.Daniel;
649 }
650
651 /**
652 * Is this book part of the minor prophets?
653 * @param book The book to test
654 * @return True if this book is a part of this section
655 */
656 public final static boolean isMinorProphet(int book)
657 {
658 return book >= Names.Hosea && book <= Names.Malachi;
659 }
660
661 /**
662 * Is this book part of the Gospels?
663 * @param book The book to test
664 * @return True if this book is a part of this section
665 */
666 public final static boolean isGospel(int book)
667 {
668 return book >= Names.Matthew && book <= Names.John;
669 }
670
671 /**
672 * Is this book part of the Gospels or Acts?
673 * @param book The book to test
674 * @return True if this book is a part of this section
675 */
676 public final static boolean isGospelOrActs(int book)
677 {
678 return book >= Names.Matthew && book <= Names.Acts;
679 }
680
681 /**
682 * Is this book part of the letters?
683 * @param book The book to test
684 * @return True if this book is a part of this section
685 */
686 public final static boolean isLetter(int book)
687 {
688 return book >= Names.Romans && book <= Names.Jude;
689 }
690
691 /**
692 * What section is this book a part of?
693 * @param book The book to test
694 * @return True The section
695 * @see Books.Section
696 */
697 public final static int getSection(int book)
698 {
699 // Ordered by section size for speed
700 if (isLetter(book)) return Section.Letters; // 21
701 if (isHistory(book)) return Section.History; // 12
702 if (isMinorProphet(book)) return Section.MinorProphets; // 12
703 if (isGospelOrActs(book)) return Section.GospelsAndActs; // 5
704 if (isPentateuch(book)) return Section.Pentateuch; // 5
705 if (isPoetry(book)) return Section.Poetry; // 5
706 if (isMajorProphet(book)) return Section.MajorProphets; // 5
707 return Section.Revelation;
708 }
709
710 /**
711 * How many books are there in each of the above sections
712 * @param section The section
713 * @return The number of books in the given section
714 * @see getSection(int)
715 */
716 public final static int booksInSection(int section)
717 {
718 return books_in_section[section];
719 }
720
721 /**
722 * Get the full name of a book (e.g. "Genesis").
723 * Altered by the case setting (see setBookCase())
724 * @param idx The book number (1-66)
725 * @return The full name of the book
726 * @exception NoSuchVerseException If the book number is not valid
727 */
728 public final static String getSectionName(int section) throws NoSuchVerseException
729 {
730 if (section == 0)
731 throw new NoSuchVerseException("passg_books_section", new Object[] { new Integer(section) });
732
733 try
734 {
735 switch (book_case)
736 {
737 case CASE_LOWER:
738 return sections_lower[section-1];
739 case CASE_UPPER:
740 return sections_upper[section-1];
741 default:
742 return sections[section-1];
743 }
744 }
745 catch (ArrayIndexOutOfBoundsException ex)
746 {
747 // This is faster than doing the check explicitly, unless
748 // The exception is actually thrown, then it is a lot slower
749 // I'd like to think that the norm is to get it right
750 throw new NoSuchVerseException("passg_books_section",
751 new Object[] { new Integer(section) });
752 }
753 }
754
755 /** How the book names are reported */
756 private static int book_case = CASE_SENTANCE;
757
758 /** The resource file, for book names */
759 private static ResourceBundle resources;
760
761 /**
762 * Handy section finder. There is a bit of moderately bad programming
763 * here because com.eireneh.bible.control.map.swing.GroupVerseColor
764 * uses these numbers as an index into an array, so we shouldn't
765 * change these numbers without fixing that, however I don't imagine
766 * that this section could ever change without breaking
767 * GroupVerseColor anyway so I don't see it as a big problem.
768 */
769 public static class Section
770 {
771 public static final byte Pentateuch = 1;
772 public static final byte History = 2;
773 public static final byte Poetry = 3;
774 public static final byte MajorProphets = 4;
775 public static final byte MinorProphets = 5;
776 public static final byte GospelsAndActs = 6;
777 public static final byte Letters = 7;
778 public static final byte Revelation = 8;
779 }
780
781 /**
782 * Handy book finder
783 */
784 public static class Names
785 {
786 public static final byte Genesis = 1;
787 public static final byte Exodus = 2;
788 public static final byte Leviticus = 3;
789 public static final byte Numbers = 4;
790 public static final byte Deuteronomy = 5;
791 public static final byte Joshua = 6;
792 public static final byte Judges = 7;
793 public static final byte Ruth = 8;
794 public static final byte Samuel1 = 9;
795 public static final byte Samuel2 = 10;
796 public static final byte Kings1 = 11;
797 public static final byte Kings2 = 12;
798 public static final byte Chronicles1 = 13;
799 public static final byte Chronicles2 = 14;
800 public static final byte Ezra = 15;
801 public static final byte Nehemiah = 16;
802 public static final byte Esther = 17;
803 public static final byte Job = 18;
804 public static final byte Psalms = 19;
805 public static final byte Proberbs = 20;
806 public static final byte Ecclesiastes = 21;
807 public static final byte SongOfSolomon = 22;
808 public static final byte Isaiah = 23;
809 public static final byte Jeremiah = 24;
810 public static final byte Lamentations = 25;
811 public static final byte Ezekiel = 26;
812 public static final byte Daniel = 27;
813 public static final byte Hosea = 28;
814 public static final byte Joel = 29;
815 public static final byte Amos = 30;
816 public static final byte Obdiah = 31;
817 public static final byte Jonah = 32;
818 public static final byte Micah = 33;
819 public static final byte Nahum = 34;
820 public static final byte Habakuk = 35;
821 public static final byte Zephaniah = 36;
822 public static final byte Haggai = 37;
823 public static final byte Zechariah = 38;
824 public static final byte Malachi = 39;
825 public static final byte Matthew = 40;
826 public static final byte Mark = 41;
827 public static final byte Luke = 42;
828 public static final byte John = 43;
829 public static final byte Acts = 44;
830 public static final byte Romans = 45;
831 public static final byte Corinthians1 = 46;
832 public static final byte Corinthians2 = 47;
833 public static final byte Galatians = 48;
834 public static final byte Ephesians = 49;
835 public static final byte Philippians = 50;
836 public static final byte Colossians = 51;
837 public static final byte Thessalonians1 = 52;
838 public static final byte Thessalonians2 = 53;
839 public static final byte Timothy1 = 54;
840 public static final byte Timothy2 = 55;
841 public static final byte Titus = 56;
842 public static final byte Philemon = 57;
843 public static final byte Hebrews = 58;
844 public static final byte James = 59;
845 public static final byte Peter1 = 60;
846 public static final byte Peter2 = 61;
847 public static final byte John1 = 62;
848 public static final byte John2 = 63;
849 public static final byte John3 = 64;
850 public static final byte Jude = 65;
851 public static final byte Revelation = 66;
852 }
853
854 /** Used for methods with int[3] parameters, for the book */
855 public static final int BOOK = 0;
856
857 /** Used for methods with int[3] parameters, for the chapter */
858 public static final int CHAPTER = 1;
859
860 /** Used for methods with int[3] parameters, for the verse */
861 public static final int VERSE = 2;
862
863 /** The full names of the book of the Bible, in mixed case */
864 private static String[] full_books =
865 {
866 "Genesis", "Exodus", "Leviticus", "Numbers", "Deuteronomy",
867 "Joshua", "Judges", "Ruth", "1 Samuel", "2 Samuel",
868 "1 Kings", "2 Kings", "1 Chronicles", "2 Chronicles",
869 "Ezra", "Nehemiah", "Esther",
870 "Job", "Psalms", "Proberbs", "Ecclesiastes", "Song of Solomon",
871 "Isaiah", "Jeremiah", "Lamentations",
872 "Ezekiel", "Daniel", "Hosea", "Joel", "Amos",
873 "Obdiah", "Jonah", "Micah", "Nahum",
874 "Habakuk", "Zephaniah", "Haggai", "Zechariah", "Malachi",
875 "Matthew", "Mark", "Luke", "John", "Acts",
876 "Romans", "1 Corinthians","2 Corinthians","Galatians", "Ephesians",
877 "Philippians", "Colossians", "1 Thessalonians","2 Thessalonians",
878 "1 Timothy", "2 Timothy", "Titus", "Philemon", "Hebrews",
879 "James", "1 Peter", "2 Peter",
880 "1 John", "2 John", "3 John", "Jude", "Revelation",
881 };
882
883 /** Standard shortened names for the book of the Bible, in mixed case */
884 private static String[] short_books =
885 {
886 "Gen", "Exo", "Lev", "Num", "Deu", "Jos", "Judg", "Rut", "1Sa", "2Sa",
887 "1Ki", "2Ki", "1Ch", "2Ch", "Ezr", "Neh", "Est", "Job", "Psa", "Pro",
888 "Ecc", "Son", "Isa", "Jer", "Lam", "Eze", "Dan", "Hos", "Joe", "Amo",
889 "Obd", "Jon", "Mic", "Nah", "Hab", "Zep", "Hag", "Zec", "Mal", "Mat",
890 "Mar", "Luk", "Joh", "Act", "Rom", "1Co", "2Co", "Gal", "Eph", "Phili",
891 "Col", "1Th", "2Th", "1Ti", "2Ti", "Tit", "Phile","Heb", "Jam", "1Pe",
892 "2Pe", "1Jo", "2Jo", "3Jo", "Jude", "Rev",
893 };
894
895 /** Standard names for the sections */
896 private static String[] sections =
897 {
898 "Pentateuch",
899 "History",
900 "Poetry",
901 "MajorProphets",
902 "MinorProphets",
903 "GospelsAndActs",
904 "Letters",
905 "Revelation",
906 };
907
908 /** Alternative shortened names for the book of the Bible, in mixed case */
909 private static String[][] alt_books =
910 {
911 /* Gen */ { },
912 /* Exo */ { },
913 /* Lev */ { },
914 /* Num */ { },
915 /* Deu */ { "Dt" },
916 /* Jos */ { },
917 /* Judg */ { "Jdg" },
918 /* Rut */ { "Rth" },
919 /* 1Sa */ { },
920 /* 2Sa */ { },
921 /* 1Ki */ { },
922 /* 2Ki */ { },
923 /* 1Ch */ { },
924 /* 2Ch */ { },
925 /* Ezr */ { },
926 /* Neh */ { },
927 /* Est */ { },
928 /* Job */ { },
929 /* Psa */ { },
930 /* Pro */ { },
931 /* Ecc */ { },
932 /* Son */ { "SS" },
933 /* Isa */ { },
934 /* Jer */ { },
935 /* Lam */ { },
936 /* Eze */ { },
937 /* Dan */ { },
938 /* Hos */ { },
939 /* Joe */ { },
940 /* Amo */ { },
941 /* Obd */ { },
942 /* Jon */ { "Jnh" },
943 /* Mic */ { },
944 /* Nah */ { },
945 /* Hab */ { },
946 /* Zep */ { },
947 /* Hag */ { },
948 /* Zec */ { },
949 /* Mal */ { },
950 /* Mat */ { "Mt" },
951 /* Mar */ { "Mk" },
952 /* Luk */ { "Lk" },
953 /* Joh */ { "Jn", "Jhn" },
954 /* Act */ { },
955 /* Rom */ { },
956 /* 1Co */ { },
957 /* 2Co */ { },
958 /* Gal */ { },
959 /* Eph */ { },
960 /* Phili */ { "Php" },
961 /* Col */ { },
962 /* 1Th */ { },
963 /* 2Th */ { },
964 /* 1Ti */ { "1Tm" },
965 /* 2Ti */ { "2Tm" },
966 /* Tit */ { },
967 /* Phile */ { "Phm" },
968 /* Heb */ { },
969 /* Jam */ { "Jas" },
970 /* 1Pe */ { "1Pt" },
971 /* 2Pe */ { "1Pt" },
972 /* 1Jo */ { "1Jn" },
973 /* 2Jo */ { "2Jn" },
974 /* 3Jo */ { "3Jn" },
975 /* Jude */ { },
976 /* Rev */ { "Rv" },
977 };
978
979 /** The full names of the book of the Bible, in lower case, generated at run time */
980 private static String[] full_books_lower;
981
982 /** Standard shortened names for the book of the Bible, in lower case, generated at run time */
983 private static String[] short_books_lower;
984
985 /** Alternative shortened names for the book of the Bible, in lower case, generated at run time */
986 private static String[][] alt_books_lower;
987
988 /** The full names of the book of the Bible, in upper case, generated at run time */
989 private static String[] full_books_upper;
990
991 /** Standard shortened names for the book of the Bible, in upper case, generated at run time */
992 private static String[] short_books_upper;
993
994 /** Standard Bible section names, in upper case, generated at run time */
995 private static String[] sections_upper;
996
997 /** Standard Bible section names, in lower case, generated at run time */
998 private static String[] sections_lower;
999
1000 /* Alternative shortened names for the book of the Bible, in upper case, generated at run time */
1001 // Not needed as the lower version was only there to speed up searching.
1002 // private static String[][] alt_books_upper;
1003
1004 /** The memory jogger names for the books of the Bible */
1005 private static final String[] jog_books =
1006 {
1007 "LT", "LN", "LM", "LR", "LL", "JT", "JN", "JM", "KT", "KN",
1008 "KM", "KR", "KL", "KG", "RT", "RN", "RM", "ST", "SN", "SM",
1009 "SR", "SL", "PT", "PN", "PM", "PR", "PL", "MT", "MN", "MM",
1010 "MR", "ML", "MG", "NT", "NN", "NM", "NT", "NL", "NG", "GT",
1011 "GN", "GM", "GR", "GL", "ST", "SN", "SM", "SR", "SL", "SG",
1012 "SK", "TT", "TN", "TM", "TR", "TL", "TG", "TK", "DT", "DN",
1013 "DM", "DR", "DL", "DG", "DK", "DB",
1014 };
1015
1016 /** The memory jogger names for the numbers */
1017 private static final String[] jog_numbers =
1018 {
1019 "S", "T", "N", "M", "R", "L", "G", "K", "B", "P",
1020 };
1021
1022 /** Constant for the number of books in the Bible */
1023 private static final int books_in_bible = 66;
1024
1025 /** Constant for the number of chapters in the Bible */
1026 private static final int chapters_in_bible = 1189;
1027
1028 /** Constant for the number of chapters in each book */
1029 private static final int[] chapters_in_book =
1030 {
1031 50, 40, 27, 36, 34, 24, 21, 4, 31, 24,
1032 22, 25, 29, 36, 10, 13, 10, 42,150, 31,
1033 12, 8, 66, 52, 5, 48, 12, 14, 3, 9,
1034 1, 4, 7, 3, 3, 3, 2, 14, 4, 28,
1035 16, 24, 21, 28, 16, 16, 13, 6, 6, 4,
1036 4, 5, 3, 6, 4, 3, 1, 13, 5, 5,
1037 3, 5, 1, 1, 1, 22,
1038 };
1039
1040 /** Constant for the number of verses in the Bible */
1041 private static final int verses_in_bible = 31102;
1042
1043 /** Constant for the number of verses in each book */
1044 private static final int[] verses_in_book =
1045 {
1046 1533, 1213, 859, 1288, 959, 658, 618, 85, 810, 695,
1047 816, 719, 942, 822, 280, 406, 167, 1070, 2461, 915,
1048 222, 117, 1292, 1364, 154, 1273, 357, 197, 73, 146,
1049 21, 48, 105, 47, 56, 53, 38, 211, 55, 1071,
1050 678, 1151, 879, 1007, 433, 437, 257, 149, 155, 104,
1051 95, 89, 47, 113, 83, 46, 25, 303, 108, 105,
1052 61, 105, 13, 14, 25, 404,
1053 };
1054
1055 /** Constant for the number of verses in each chapter */
1056 private static final int[][] verses_in_chapter =
1057 {
1058 { 31, 25, 24, 26, 32, 22, 24, 22, 29, 32, 32, 20, 18, 24, 21, 16, 27, 33, 38, 18, 34, 24, 20, 67, 34, 35, 46, 22, 35, 43, 55, 32, 20, 31, 29, 43, 36, 30, 23, 23, 57, 38, 34, 34, 28, 34, 31, 22, 33, 26 },
1059 { 22, 25, 22, 31, 23, 30, 25, 32, 35, 29, 10, 51, 22, 31, 27, 36, 16, 27, 25, 26, 36, 31, 33, 18, 40, 37, 21, 43, 46, 38, 18, 35, 23, 35, 35, 38, 29, 31, 43, 38 },
1060 { 17, 16, 17, 35, 19, 30, 38, 36, 24, 20, 47, 8, 59, 57, 33, 34, 16, 30, 37, 27, 24, 33, 44, 23, 55, 46, 34 },
1061 { 54, 34, 51, 49, 31, 27, 89, 26, 23, 36, 35, 16, 33, 45, 41, 50, 13, 32, 22, 29, 35, 41, 30, 25, 18, 65, 23, 31, 40, 16, 54, 42, 56, 29, 34, 13 },
1062 { 46, 37, 29, 49, 33, 25, 26, 20, 29, 22, 32, 32, 18, 29, 23, 22, 20, 22, 21, 20, 23, 30, 25, 22, 19, 19, 26, 68, 29, 20, 30, 52, 29, 12 },
1063 { 18, 24, 17, 24, 15, 27, 26, 35, 27, 43, 23, 24, 33, 15, 63, 10, 18, 28, 51, 9, 45, 34, 16, 33 },
1064 { 36, 23, 31, 24, 31, 40, 25, 35, 57, 18, 40, 15, 25, 20, 20, 31, 13, 31, 30, 48, 25 },
1065 { 22, 23, 18, 22 },
1066 { 28, 36, 21, 22, 12, 21, 17, 22, 27, 27, 15, 25, 23, 52, 35, 23, 58, 30, 24, 42, 15, 23, 29, 22, 44, 25, 12, 25, 11, 31, 13 },
1067 { 27, 32, 39, 12, 25, 23, 29, 18, 13, 19, 27, 31, 39, 33, 37, 23, 29, 33, 43, 26, 22, 51, 39, 25 },
1068 { 53, 46, 28, 34, 18, 38, 51, 66, 28, 29, 43, 33, 34, 31, 34, 34, 24, 46, 21, 43, 29, 53 },
1069 { 18, 25, 27, 44, 27, 33, 20, 29, 37, 36, 21, 21, 25, 29, 38, 20, 41, 37, 37, 21, 26, 20, 37, 20, 30 },
1070 { 54, 55, 24, 43, 26, 81, 40, 40, 44, 14, 47, 40, 14, 17, 29, 43, 27, 17, 19, 8, 30, 19, 32, 31, 31, 32, 34, 21, 30 },
1071 { 17, 18, 17, 22, 14, 42, 22, 18, 31, 19, 23, 16, 22, 15, 19, 14, 19, 34, 11, 37, 20, 12, 21, 27, 28, 23, 9, 27, 36, 27, 21, 33, 25, 33, 27, 23 },
1072 { 11, 70, 13, 24, 17, 22, 28, 36, 15, 44 },
1073 { 11, 20, 32, 23, 19, 19, 73, 18, 38, 39, 36, 47, 31 },
1074 { 22, 23, 15, 17, 14, 14, 10, 17, 32, 03 },
1075 { 22, 13, 26, 21, 27, 30, 21, 22, 35, 22, 20, 25, 28, 22, 35, 22, 16, 21, 29, 29, 34, 30, 17, 25, 6, 14, 23, 28, 25, 31, 40, 22, 33, 37, 16, 33, 24, 41, 30, 24, 34, 17 },
1076 { 6, 12, 8, 8, 12, 10, 17, 9, 20, 18, 7, 8, 6, 7, 5, 11, 15, 50, 14, 9, 13, 31, 6, 10, 22, 12, 14, 9, 11, 12, 24, 11, 22, 22, 28, 12, 40, 22, 13, 17, 13, 11, 5, 26, 17, 11, 9, 14, 20, 23, 19, 9, 6, 7, 23, 13, 11, 11, 17, 12, 8, 12, 11, 10, 13, 20, 7, 35, 36, 5, 24, 20, 28, 23, 10, 12, 20, 72, 13, 19, 16, 8, 18, 12, 13, 17, 7, 18, 52, 17, 16, 15, 5, 23, 11, 13, 12, 9, 9, 5, 8, 28, 22, 35, 45, 48, 43, 13, 31, 7, 10, 10, 9, 8, 18, 19, 2, 29,176, 7, 8, 9, 4, 8, 5, 6, 5, 6, 8, 8, 3, 18, 3, 3, 21, 26, 9, 8, 24, 13, 10, 7, 12, 15, 21, 10, 20, 14, 9, 6 },
1077 { 33, 22, 35, 27, 23, 35, 27, 36, 18, 32, 31, 28, 25, 35, 33, 33, 28, 24, 29, 30, 31, 29, 35, 34, 28, 28, 27, 28, 27, 33, 31 },
1078 { 18, 26, 22, 16, 20, 12, 29, 17, 18, 20, 10, 14 },
1079 { 17, 17, 11, 16, 16, 13, 13, 14 },
1080 { 31, 22, 26, 06, 30, 13, 25, 22, 21, 34, 16, 06, 22, 32, 9, 14, 14, 07, 25, 06, 17, 25, 18, 23, 12, 21, 13, 29, 24, 33, 9, 20, 24, 17, 10, 22, 38, 22, 8, 31, 29, 25, 28, 28, 25, 13, 15, 22, 26, 11, 23, 15, 12, 17, 13, 12, 21, 14, 21, 22, 11, 12, 19, 12, 25, 24 },
1081 { 19, 37, 25, 31, 31, 30, 34, 22, 26, 25, 23, 17, 27, 22, 21, 21, 27, 23, 15, 18, 14, 30, 40, 10, 38, 24, 22, 17, 32, 24, 40, 44, 26, 22, 19, 32, 21, 28, 18, 16, 18, 22, 13, 30, 5, 28, 7, 47, 39, 46, 64, 34 },
1082 { 22, 22, 66, 22, 22 },
1083 { 28, 10, 27, 17, 17, 14, 27, 18, 11, 22, 25, 28, 23, 23, 8, 63, 24, 32, 14, 49, 32, 31, 49, 27, 17, 21, 36, 26, 21, 26, 18, 32, 33, 31, 15, 38, 28, 23, 29, 49, 26, 20, 27, 31, 25, 24, 23, 35 },
1084 { 21, 49, 30, 37, 31, 28, 28, 27, 27, 21, 45, 13 },
1085 { 11, 23, 05, 19, 15, 11, 16, 14, 17, 15, 12, 14, 16, 9 },
1086 { 20, 32, 21 },
1087 { 15, 16, 15, 13, 27, 14, 17, 14, 15 },
1088 { 21 },
1089 { 17, 10, 10, 11 },
1090 { 16, 13, 12, 13, 15, 16, 20 },
1091 { 15, 13, 19 },
1092 { 17, 20, 19 },
1093 { 18, 15, 20 },
1094 { 15, 23 },
1095 { 21, 13, 10, 14, 11, 15, 14, 23, 17, 12, 17, 14, 9, 21 },
1096 { 14, 17, 18, 06 },
1097 { 25, 23, 17, 25, 48, 34, 29, 34, 38, 42, 30, 50, 58, 36, 39, 28, 27, 35, 30, 34, 46, 46, 39, 51, 46, 75, 66, 20 },
1098 { 45, 28, 35, 41, 43, 56, 37, 38, 50, 52, 33, 44, 37, 72, 47, 20 },
1099 { 80, 52, 38, 44, 39, 49, 50, 56, 62, 42, 54, 59, 35, 35, 32, 31, 37, 43, 48, 47, 38, 71, 56, 53 },
1100 { 51, 25, 36, 54, 47, 71, 53, 59, 41, 42, 57, 50, 38, 31, 27, 33, 26, 40, 42, 31, 25 },
1101 { 26, 47, 26, 37, 42, 15, 60, 40, 43, 48, 30, 25, 52, 28, 41, 40, 34, 28, 41, 38, 40, 30, 35, 27, 27, 32, 44, 31 },
1102 { 32, 29, 31, 25, 21, 23, 25, 39, 33, 21, 36, 21, 14, 23, 33, 27 },
1103 { 31, 16, 23, 21, 13, 20, 40, 13, 27, 33, 34, 31, 13, 40, 58, 24 },
1104 { 24, 17, 18, 18, 21, 18, 16, 24, 15, 18, 33, 21, 14 },
1105 { 24, 21, 29, 31, 26, 18 },
1106 { 23, 22, 21, 32, 33, 24 },
1107 { 30, 30, 21, 23 },
1108 { 29, 23, 25, 18 },
1109 { 10, 20, 13, 18, 28 },
1110 { 12, 17, 18 },
1111 { 20, 15, 16, 16, 25, 21 },
1112 { 18, 26, 17, 22 },
1113 { 16, 15, 15 },
1114 { 25 },
1115 { 14, 18, 19, 16, 14, 20, 28, 13, 28, 39, 40, 29, 25 },
1116 { 27, 26, 18, 17, 20 },
1117 { 25, 25, 22, 19, 14 },
1118 { 21, 22, 18 },
1119 { 10, 29, 24, 21, 21 },
1120 { 13 },
1121 { 14 },
1122 { 25 },
1123 { 20, 29, 22, 11, 14, 17, 17, 13, 21, 11, 19, 17, 18, 20, 8, 21, 18, 24, 21, 15, 27, 21 }
1124 };
1125
1126 /** Constant for the ordinal number of the first verse in each book */
1127 private static final int[] ordinal_at_start_of_book =
1128 {
1129 1, 1534, 2747, 3606, 4894, 5853, 6511, 7129, 7214, 8024,
1130 8719, 9535, 10254, 11196, 12018, 12298, 12704, 12871, 13941, 16402,
1131 17317, 17539, 17656, 18948, 20312, 20466, 21739, 22096, 22293, 22366,
1132 22512, 22533, 22581, 22686, 22733, 22789, 22842, 22880, 23091, 23146,
1133 24217, 24895, 26046, 26925, 27932, 28365, 28802, 29059, 29208, 29363,
1134 29467, 29562, 29651, 29698, 29811, 29894, 29940, 29965, 30268, 30376,
1135 30481, 30542, 30647, 30660, 30674, 30699,
1136 };
1137
1138 /**
1139 * Constant for the ordinal number of the first verse in each chapter.
1140 * Warning if you regenerate this code (from the code at the bottom of
1141 * this module) then you will need to cut the psalms line in half to
1142 * get it to compile under JBuilder.
1143 */
1144 private static final int[][] ordinal_at_start_of_chapter =
1145 {
1146 { 1, 32, 57, 81, 107, 139, 161, 185, 207, 236, 268, 300, 320, 338, 362, 383, 399, 426, 459, 497, 515, 549, 573, 593, 660, 694, 729, 775, 797, 832, 875, 930, 962, 982, 1013, 1042, 1085, 1121, 1151, 1174, 1197, 1254, 1292, 1326, 1360, 1388, 1422, 1453, 1475, 1508, },
1147 { 1534, 1556, 1581, 1603, 1634, 1657, 1687, 1712, 1744, 1779, 1808, 1818, 1869, 1891, 1922, 1949, 1985, 2001, 2028, 2053, 2079, 2115, 2146, 2179, 2197, 2237, 2274, 2295, 2338, 2384, 2422, 2440, 2475, 2498, 2533, 2568, 2606, 2635, 2666, 2709, },
1148 { 2747, 2764, 2780, 2797, 2832, 2851, 2881, 2919, 2955, 2979, 2999, 3