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: BibleNames.java 2223 2012-01-26 21:28:02Z dmsmith $
21   */
22  package org.crosswire.jsword.versification;
23  
24  import java.util.HashMap;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.MissingResourceException;
28  import java.util.ResourceBundle;
29  
30  import org.crosswire.common.util.CWClassLoader;
31  import org.crosswire.common.util.ClassUtil;
32  import org.crosswire.common.util.StringUtil;
33  
34  /**
35   * BibleNames deals with locale sensitive BibleBook name lookup conversions.
36   *
37   * @see gnu.lgpl.License for license details.<br>
38   *      The copyright to this program is held by it's authors.
39   * @author Joe Walker [joe at eireneh dot com]
40   * @author DM Smith [dmsmith555 at yahoo dot com]
41   */
42  /* package */ final class BibleNames {
43      /**
44       * Create BibleNames for the given locale
45       */
46      /* package */ BibleNames(Locale locale) {
47          this.locale = locale;
48          initialize();
49      }
50  
51      /* package */ BookName getBookName(BibleBook book) {
52          return books[book.ordinal()];
53      }
54  
55      /**
56       * Get the preferred name of a book. Altered by the case setting (see
57       * setBookCase() and isFullBookName())
58       *
59       * @param book
60       *            The book of the Bible
61       * @return The full name of the book
62       */
63      /* package */ String getPreferredName(BibleBook book) {
64          return getBookName(book).getPreferredName();
65      }
66  
67      /**
68       * Get the full name of a book (e.g. "Genesis"). Altered by the case setting
69       * (see setBookCase())
70       *
71       * @param book
72       *            The book of the Bible
73       * @return The full name of the book
74       */
75      /* package */ String getLongName(BibleBook book) {
76          return getBookName(book).getLongName();
77      }
78  
79      /**
80       * Get the short name of a book (e.g. "Gen"). Altered by the case setting
81       * (see setBookCase())
82       *
83       * @param book
84       *            The book of the Bible
85       * @return The short name of the book
86       */
87      /* package */ String getShortName(BibleBook book) {
88          return getBookName(book).getShortName();
89      }
90  
91      /**
92       * Get number of a book from its name.
93       *
94       * @param find
95       *            The string to identify
96       * @return The BibleBook, On error null
97       */
98      /* package */ BibleBook getBook(String find) {
99          String match = BookName.normalize(find, locale);
100 
101         BookName bookName = fullBooksMap.get(match);
102         if (bookName != null) {
103             return bookName.getBook();
104         }
105 
106         bookName = shortBooksMap.get(match);
107         if (bookName != null) {
108             return bookName.getBook();
109         }
110 
111         bookName = altBooksMap.get(match);
112         if (bookName != null) {
113             return bookName.getBook();
114         }
115 
116         for (int i = 0; i < books.length; i++) {
117             bookName = books[i];
118             if (bookName.match(match)) {
119                 return bookName.getBook();
120             }
121         }
122 
123         return null;
124     }
125 
126     /**
127      * Is the given string a valid book name. If this method returns true then
128      * getBook() will return a BibleBook and not null.
129      *
130      * @param find
131      *            The string to identify
132      * @return true if the book name is known
133      */
134     /* package */ boolean isBookName(String find) {
135         return getBook(find) != null;
136     }
137 
138     /**
139      * Load up the resources for Bible book and section names, and cache the
140      * upper and lower versions of them.
141      */
142     private void initialize() {
143         int booksInBible = BibleBook.values().length;
144 
145         books = new BookName[booksInBible];
146 
147         // Create the book name maps
148         fullBooksMap = new HashMap<String, BookName>(booksInBible);
149         shortBooksMap = new HashMap<String, BookName>(booksInBible);
150 
151         altBooksMap = new HashMap<String, BookName>(booksInBible);
152 
153         String className = BibleNames.class.getName();
154         String shortClassName = ClassUtil.getShortClassName(className);
155         ResourceBundle resources = ResourceBundle.getBundle(shortClassName, locale, CWClassLoader.instance(BibleNames.class));
156 
157         for (BibleBook book : BibleBook.values()) {
158             String osisName = book.getOSIS();
159 
160             String fullBook = getString(resources, osisName + FULL_KEY);
161 
162             String shortBook = getString(resources, osisName + SHORT_KEY);
163             if (shortBook.length() == 0) {
164                 shortBook = fullBook;
165             }
166 
167             String altBook = getString(resources, osisName + ALT_KEY);
168 
169             BookName bookName = new BookName(locale, BibleBook.fromOSIS(osisName), fullBook, shortBook, altBook);
170             books[book.ordinal()] = bookName;
171 
172             fullBooksMap.put(bookName.getNormalizedLongName(), bookName);
173 
174             shortBooksMap.put(bookName.getNormalizedShortName(), bookName);
175 
176             String[] alternates = StringUtil.split(BookName.normalize(altBook, locale), ',');
177 
178             for (int j = 0; j < alternates.length; j++) {
179                 altBooksMap.put(alternates[j], bookName);
180             }
181 
182         }
183     }
184 
185     /*
186      * Helper to make the code more readable.
187      */
188     private String getString(ResourceBundle resources, String key) {
189         try {
190             return resources.getString(key);
191         } catch (MissingResourceException e) {
192             assert false;
193         }
194         return null;
195     }
196 
197     private static final String FULL_KEY = ".Full";
198     private static final String SHORT_KEY = ".Short";
199     private static final String ALT_KEY = ".Alt";
200 
201     private BookName[] books;
202 
203     /** The locale for the Bible Names */
204     private Locale locale;
205 
206     /**
207      * The full names of the book of the Bible, normalized, generated at runtime
208      */
209     private Map<String, BookName> fullBooksMap;
210 
211     /**
212      * Standard shortened names for the book of the Bible, normalized, generated
213      * at runtime.
214      */
215     private Map<String, BookName> shortBooksMap;
216 
217     /**
218      * Alternative shortened names for the book of the Bible, normalized,
219      * generated at runtime
220      */
221     private Map<String, BookName> altBooksMap;
222 }
223