/**
* Distribution License:
* JSword is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License, version 2.1 as published by
* the Free Software Foundation. This program is distributed in the hope
* that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The License is available on the internet at:
* http://www.gnu.org/copyleft/lgpl.html
* or by writing to:
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307, USA
*
* Copyright: 2007
* The copyright to this program is held by it's authors.
*
* ID: $Id: BookName.java 2140 2011-04-03 02:07:01Z dmsmith $
*/
package org.crosswire.jsword.versification;
import java.util.Locale;
import java.util.regex.Pattern;
import org.crosswire.common.util.StringUtil;
import org.crosswire.jsword.book.CaseType;
/**
* BookName represents the different ways a book of the bible is named.
*
* @see gnu.lgpl.License for license details.<br>
* The copyright to this program is held by it's authors.
* @author DM Smith [dmsmith555 at yahoo dot com]
*/
public final class BookName {
/**
* Create a BookName for a Book of the Bible in a given language.
*
* @param locale
* the language of this BookName
* @param book
* the Book's canonical number
* @param longName
* the Book's long name
* @param shortName
* the Book's short name, if any
* @param alternateNames
* optional comma separated list of alternates for the Book
*/
public BookName(Locale locale, BibleBook book, String longName, String shortName, String alternateNames) {
this.locale = locale;
this.book = book;
this.longName = longName;
this.normalizedLongName = normalize(longName, locale);
this.shortName = shortName;
this.normalizedShortName = normalize(shortName, locale);
if (alternateNames != null) {
this.alternateNames = StringUtil.split(normalize(alternateNames, locale), ',');
}
}
/**
* Get the BibleBook to which this set of names is tied.
*
* @return The book
*/
public BibleBook getBook() {
return book;
}
/**
* Get the preferred name of a book. Altered by the case setting (see
* setBookCase() and isFullBookName())
*
* @return The preferred name of the book
*/
public String getPreferredName() {
if (BookName.isFullBookName()) {
return getLongName();
}
return getShortName();
}
/**
* Get the full name of a book (e.g. "Genesis"). Altered by the case setting
* (see setBookCase())
*
* @return The full name of the book
*/
public String getLongName() {
CaseType caseType = BookName.getDefaultCase();
if (caseType == CaseType.LOWER) {
return longName.toLowerCase(locale);
}
if (caseType == CaseType.UPPER) {
return longName.toUpperCase(locale);
}
return longName;
}
/**
* Get the short name of a book (e.g. "Gen"). Altered by the case setting
* (see setBookCase())
*
* @return The short name of the book
*/
public String getShortName() {
CaseType caseType = BookName.getDefaultCase();
if (caseType == CaseType.LOWER) {
return shortName.toLowerCase(locale);
}
if (caseType == CaseType.UPPER) {
return shortName.toUpperCase(locale);
}
return shortName;
}
/**
* @return the normalizedLongName
*/
public String getNormalizedLongName() {
return normalizedLongName;
}
/**
* @return the normalizedShortName
*/
public String getNormalizedShortName() {
return normalizedShortName;
}
/**
* Match the normalized name as closely as possible. It will match if:
* <ol>
* <li>it is a prefix of a normalized alternate name</li>
* <li>a normalized alternate name is a prefix of it</li>
* <li>it is a prefix of a normalized long name</li>
* <li>it is a prefix of a normalized short name</li>
* <li>a normalized short name is a prefix of it</li>
*
* @param normalizedName
* the already normalized name to match against.
* @return true of false
*/
public boolean match(String normalizedName) {
// Does it match one of the alternative versions
for (int j = 0; j < alternateNames.length; j++) {
String targetBookName = alternateNames[j];
if (targetBookName.startsWith(normalizedName) || normalizedName.startsWith(targetBookName)) {
return true;
}
}
// Does it match a long version of the book
if (normalizedLongName.startsWith(normalizedName)) {
return true;
}
// or a short version
//MJD added check for empty normalizedShortName
if (normalizedShortName.startsWith(normalizedName) || (normalizedShortName.length()>0 && normalizedName.startsWith(normalizedShortName))) {
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return book.hashCode();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final BookName other = (BookName) obj;
return book == other.book;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getPreferredName();
}
/**
* Normalize by stripping punctuation and whitespace and lowercasing.
*
* @param str
* the string to normalize
* @return the normalized string
*/
public static String normalize(String str, Locale locale) {
return normPattern.matcher(str).replaceAll("").toLowerCase(locale);
}
/**
* This is only used by config.
*
* @param bookCase
* The new case to use for reporting book names
* @exception IllegalArgumentException
* If the case is not between 0 and 2
* @see #getCase()
*/
public static void setCase(int bookCase) {
BookName.bookCase = CaseType.fromInteger(bookCase);
}
/**
* This is only used by config
*
* @return The current case setting
* @see #setCase(CaseType)
*/
public static int getCase() {
return BookName.bookCase.toInteger();
}
/**
* How do we report the names of the books?. These are static. This is on
* the assumption that we will not want to have different sections of the
* app using a different format. I expect this to be a good assumption, and
* it saves passing a Book class around everywhere. CaseType.MIXED is not
* allowed
*
* @param newBookCase
* The new case to use for reporting book names
* @exception IllegalArgumentException
* If the case is not between 0 and 2
* @see #getCase()
*/
public static void setCase(CaseType newBookCase) {
BookName.bookCase = newBookCase;
}
/**
* This is only used by config
*
* @return Whether the name is long or short. Default is Full (true).
* @see #setFullBookName(boolean)
*/
public static boolean isFullBookName() {
return BookName.fullBookName;
}
/**
* Set whether the name should be full or abbreviated, long or short.
*
* @param fullName
* The new case to use for reporting book names
* @see #isFullBookName()
*/
public static void setFullBookName(boolean fullName) {
BookName.fullBookName = fullName;
}
/**
* How do we report the names of the books?.
*
* @return The current case setting
* @see #setCase(int)
*/
public static CaseType getDefaultCase() {
return BookName.bookCase;
}
/** remove spaces and some punctuation in Book Name (make sure , is allowed) */
private static Pattern normPattern = Pattern.compile("[. ]");
private BibleBook book;
private String longName;
private String normalizedLongName;
private String shortName;
private String normalizedShortName;
private String[] alternateNames;
/** The locale for the Book Name */
private Locale locale;
/** How the book names are reported. */
private static CaseType bookCase = CaseType.SENTENCE;
/** Whether long or short, full or abbreviated names are used. */
private static boolean fullBookName = true;
}