| BookName.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 * © CrossWire Bible Society, 2007 - 2016
18 *
19 */
20 package org.crosswire.jsword.versification;
21
22 import java.util.Locale;
23 import java.util.regex.Pattern;
24
25 import org.crosswire.common.util.StringUtil;
26 import org.crosswire.jsword.book.CaseType;
27
28 /**
29 * BookName represents the different ways a book of the bible is named.
30 *
31 * @see gnu.lgpl.License The GNU Lesser General Public License for details.
32 * @author DM Smith
33 */
34 public final class BookName {
35 /**
36 * Create a BookName for a Book of the Bible in a given language.
37 *
38 * @param locale
39 * the language of this BookName
40 * @param book
41 * the Book's canonical number
42 * @param longName
43 * the Book's long name
44 * @param shortName
45 * the Book's short name, if any
46 * @param alternateNames
47 * optional comma separated list of alternates for the Book
48 */
49 public BookName(Locale locale, BibleBook book, String longName, String shortName, String alternateNames) {
50 this.locale = locale;
51 this.book = book;
52 this.longName = longName;
53 this.normalizedLongName = normalize(longName, locale);
54 this.shortName = shortName;
55 this.normalizedShortName = normalize(shortName, locale);
56
57 if (alternateNames != null) {
58 this.alternateNames = StringUtil.split(normalize(alternateNames, locale), ',');
59 }
60 }
61
62 /**
63 * Get the BibleBook to which this set of names is tied.
64 *
65 * @return The book
66 */
67 public BibleBook getBook() {
68 return book;
69 }
70
71 /**
72 * Get the preferred name of a book. Altered by the case setting (see
73 * setBookCase() and isFullBookName())
74 *
75 * @return The preferred name of the book
76 */
77 public String getPreferredName() {
78 if (BookName.isFullBookName()) {
79 return getLongName();
80 }
81 return getShortName();
82 }
83
84 /**
85 * Get the full name of a book (e.g. "Genesis"). Altered by the case setting
86 * (see setBookCase())
87 *
88 * @return The full name of the book
89 */
90 public String getLongName() {
91 CaseType caseType = BookName.getDefaultCase();
92
93 if (caseType == CaseType.LOWER) {
94 return longName.toLowerCase(locale);
95 }
96
97 if (caseType == CaseType.UPPER) {
98 return longName.toUpperCase(locale);
99 }
100
101 return longName;
102 }
103
104 /**
105 * Get the short name of a book (e.g. "Gen"). Altered by the case setting
106 * (see setBookCase())
107 *
108 * @return The short name of the book
109 */
110 public String getShortName() {
111 CaseType caseType = BookName.getDefaultCase();
112
113 if (caseType == CaseType.LOWER) {
114 return shortName.toLowerCase(locale);
115 }
116
117 if (caseType == CaseType.UPPER) {
118 return shortName.toUpperCase(locale);
119 }
120
121 return shortName;
122 }
123
124 /**
125 * @return the normalizedLongName
126 */
127 public String getNormalizedLongName() {
128 return normalizedLongName;
129 }
130
131 /**
132 * @return the normalizedShortName
133 */
134 public String getNormalizedShortName() {
135 return normalizedShortName;
136 }
137
138 /**
139 * Match the normalized name as closely as possible. It will match if:
140 * <ol>
141 * <li>it is a prefix of a normalized alternate name</li>
142 * <li>a normalized alternate name is a prefix of it</li>
143 * <li>it is a prefix of a normalized long name</li>
144 * <li>it is a prefix of a normalized short name</li>
145 * <li>a normalized short name is a prefix of it</li>
146 * </ol>
147 *
148 * @param normalizedName
149 * the already normalized name to match against.
150 * @return true of false
151 */
152 public boolean match(String normalizedName) {
153 // Does it match one of the alternative versions
154 for (int j = 0; j < alternateNames.length; j++) {
155 String targetBookName = alternateNames[j];
156 if (targetBookName.startsWith(normalizedName) || normalizedName.startsWith(targetBookName)) {
157 return true;
158 }
159 }
160
161 // Does it match a long version of the book
162 if (normalizedLongName.startsWith(normalizedName)) {
163 return true;
164 }
165
166 // or a short version
167 if (normalizedShortName.startsWith(normalizedName) || (normalizedShortName.length() > 0 && normalizedName.startsWith(normalizedShortName))) {
168 return true;
169 }
170
171 return false;
172 }
173
174 /*
175 * (non-Javadoc)
176 *
177 * @see java.lang.Object#hashCode()
178 */
179 @Override
180 public int hashCode() {
181 return book.hashCode();
182 }
183
184 /*
185 * (non-Javadoc)
186 *
187 * @see java.lang.Object#equals(java.lang.Object)
188 */
189 @Override
190 public boolean equals(Object obj) {
191 if (this == obj) {
192 return true;
193 }
194
195 if (obj == null) {
196 return false;
197 }
198
199 if (getClass() != obj.getClass()) {
200 return false;
201 }
202
203 final BookName other = (BookName) obj;
204 return book == other.book;
205 }
206
207 /*
208 * (non-Javadoc)
209 *
210 * @see java.lang.Object#toString()
211 */
212 @Override
213 public String toString() {
214 return getPreferredName();
215 }
216
217 /**
218 * Normalize by stripping punctuation and whitespace and lowercasing.
219 *
220 * @param str
221 * the string to normalize
222 * @param locale the locale that should be used for normalization
223 * @return the normalized string
224 */
225 public static String normalize(String str, Locale locale) {
226 return normPattern.matcher(str).replaceAll("").toLowerCase(locale);
227 }
228
229 /**
230 * This is only used by config.
231 *
232 * @param bookCase
233 * The new case to use for reporting book names
234 * @exception IllegalArgumentException
235 * If the case is not between 0 and 2
236 * @see #getCase()
237 */
238 public static void setCase(int bookCase) {
239 BookName.bookCase = CaseType.fromInteger(bookCase);
240 }
241
242 /**
243 * How do we report the names of the books?. These are static. This is on
244 * the assumption that we will not want to have different sections of the
245 * app using a different format. I expect this to be a good assumption, and
246 * it saves passing a Book class around everywhere. CaseType.MIXED is not
247 * allowed
248 *
249 * @param newBookCase
250 * The new case to use for reporting book names
251 * @exception IllegalArgumentException
252 * If the case is not between 0 and 2
253 * @see #getCase()
254 */
255 public static void setCase(CaseType newBookCase) {
256 BookName.bookCase = newBookCase;
257 }
258
259 /**
260 * This is only used by config
261 *
262 * @return The current case setting
263 * @see #setCase(CaseType)
264 */
265 public static int getCase() {
266 return BookName.bookCase.toInteger();
267 }
268
269 /**
270 * This is only used by config
271 *
272 * @return Whether the name is long or short. Default is Full (true).
273 * @see #setFullBookName(boolean)
274 */
275 public static boolean isFullBookName() {
276 return BookName.fullBookName;
277 }
278
279 /**
280 * Set whether the name should be full or abbreviated, long or short.
281 *
282 * @param fullName
283 * The new case to use for reporting book names
284 * @see #isFullBookName()
285 */
286 public static void setFullBookName(boolean fullName) {
287 BookName.fullBookName = fullName;
288 }
289
290 /**
291 * How do we report the names of the books?.
292 *
293 * @return The current case setting
294 * @see #setCase(int)
295 */
296 public static CaseType getDefaultCase() {
297 return BookName.bookCase;
298 }
299
300 /** remove spaces and some punctuation in Book Name (make sure , is allowed) */
301 private static Pattern normPattern = Pattern.compile("[. ]");
302
303 private BibleBook book;
304 private String longName;
305 private String normalizedLongName;
306 private String shortName;
307 private String normalizedShortName;
308 private String[] alternateNames;
309
310 /** The locale for the Book Name */
311 private Locale locale;
312
313 /** How the book names are reported. */
314 private static CaseType bookCase = CaseType.SENTENCE;
315
316 /** Whether long or short, full or abbreviated names are used. */
317 private static boolean fullBookName = true;
318
319 }
320