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, 2005 - 2016
18   *
19   */
20  package org.crosswire.jsword.book.basic;
21  
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.crosswire.common.util.Language;
28  import org.crosswire.common.util.StringUtil;
29  import org.crosswire.common.xml.XMLUtil;
30  import org.crosswire.jsword.book.BookCategory;
31  import org.crosswire.jsword.book.BookDriver;
32  import org.crosswire.jsword.book.OSISUtil;
33  import org.crosswire.jsword.passage.VerseKey;
34  import org.jdom2.Document;
35  import org.jdom2.Element;
36  
37  /**
38   * DefaultBookMetaData is an implementation of the of the BookMetaData
39   * interface. A less complete implementation design for inheritance is available
40   * in AbstractBookMetaData where the complexity is in the setup rather than the
41   * inheritance. DefaultBookMetaData is probably the preferred implementation.
42   * 
43   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
44   * @author Joe Walker
45   */
46  public class DefaultBookMetaData extends AbstractBookMetaData {
47      /**
48       * Ctor with some default values. A call to setBook() is still required
49       * after this ctor is called
50       * @param driver the driver for this book
51       * @param name the name of this book
52       * @param type the type of this book
53       */
54      public DefaultBookMetaData(BookDriver driver, String name, BookCategory type) {
55          props = new HashMap<String, String>();
56          setDriver(driver);
57          setName(name);
58          setBookCategory(type);
59          setLanguage(Language.DEFAULT_LANG); // Default language
60      }
61  
62      /* (non-Javadoc)
63       * @see org.crosswire.jsword.book.BookMetaData#getBookCharset()
64       */
65      public String getBookCharset() {
66          return DEFAULT_CHARSET;
67      }
68  
69      /* (non-Javadoc)
70       * @see org.crosswire.jsword.book.BookMetaData#getPropertyKeys()
71       */
72      public Set<String> getPropertyKeys() {
73          return Collections.unmodifiableSet(props.keySet());
74      }
75  
76      /* (non-Javadoc)
77       * @see org.crosswire.jsword.book.BookMetaData#getProperty(java.lang.String)
78       */
79      public String getProperty(String key) {
80          if (KEY_LANGUAGE.equals(key)) {
81              return getLanguage().getName();
82          }
83          return props.get(key);
84      }
85  
86      /* (non-Javadoc)
87       * @see org.crosswire.jsword.book.BookMetaData#setProperty(java.lang.String, java.lang.String)
88       */
89      public void setProperty(String key, String value) {
90          props.put(key, value);
91      }
92  
93      /* (non-Javadoc)
94       * @see org.crosswire.jsword.book.BookMetaData#putProperty(java.lang.String, java.lang.String)
95       */
96      @Override
97      public void putProperty(String key, String value) {
98          setProperty(key, value);
99      }
100 
101     /* (non-Javadoc)
102      * @see org.crosswire.jsword.book.BookMetaData#putProperty(java.lang.String, java.lang.String, boolean)
103      */
104     public void putProperty(String key, String value, boolean forFrontend) {
105         setProperty(key, value);
106     }
107 
108     /* (non-Javadoc)
109      * @see org.crosswire.jsword.book.BookMetaData#getBookCategory()
110      */
111     public BookCategory getBookCategory() {
112         return type;
113     }
114 
115     /* (non-Javadoc)
116      * @see org.crosswire.jsword.book.BookMetaData#getName()
117      */
118     public String getName() {
119         return name;
120     }
121 
122     /* (non-Javadoc)
123      * @see org.crosswire.jsword.book.BookMetaData#getAbbreviation()
124      */
125     public String getAbbreviation() {
126         return initials;
127     }
128 
129     /* (non-Javadoc)
130      * @see org.crosswire.jsword.book.BookMetaData#getInitials()
131      */
132     public String getInitials() {
133         return initials;
134     }
135 
136     /* (non-Javadoc)
137      * @see org.crosswire.jsword.book.BookMetaData#isLeftToRight()
138      */
139     public boolean isLeftToRight() {
140         return getLanguage().isLeftToRight();
141     }
142 
143     /**
144      * See note on setName() for side effect on setInitials(). If a value of
145      * null is used then the initials are defaulted using the name
146      * 
147      * @see DefaultBookMetaData#setName(String)
148      * @param initials
149      *            The initials to set.
150      */
151     public void setInitials(String initials) {
152         if (initials == null) {
153             if (name == null) {
154                 this.initials = "";
155             } else {
156                 this.initials = StringUtil.getInitials(name);
157             }
158         } else {
159             this.initials = initials;
160         }
161     }
162 
163     /**
164      * Setting the name also sets some default initials, so if you wish to set
165      * some specific initials then it should be done after setting the name.
166      * 
167      * @see DefaultBookMetaData#setInitials(String)
168      * @param name
169      *            The name to set.
170      */
171     public void setName(String name) {
172         this.name = name;
173 
174         putProperty(KEY_NAME, this.name);
175 
176         setInitials(StringUtil.getInitials(name));
177     }
178 
179     /**
180      * @param aType
181      *            The type to set.
182      */
183     public void setBookCategory(BookCategory aType) {
184         BookCategory t = aType;
185         if (t == null) {
186             t = BookCategory.BIBLE;
187         }
188         type = t;
189 
190         putProperty(KEY_CATEGORY, type.toString());
191     }
192 
193     /**
194      * @param typestr
195      *            The string version of the type to set.
196      */
197     public void setType(String typestr) {
198         BookCategory newType = null;
199         if (typestr != null) {
200             newType = BookCategory.fromString(typestr);
201         }
202 
203         setBookCategory(newType);
204     }
205 
206     /* (non-Javadoc)
207      * @see org.crosswire.jsword.book.basic.AbstractBookMetaData#toOSIS()
208      */
209     @Override
210     public Document toOSIS() {
211         OSISUtil.OSISFactory factory = OSISUtil.factory();
212         Element ele = factory.createTable();
213         addRow(factory, ele, "Initials", getInitials());
214         addRow(factory, ele, "Description", getName());
215         addRow(factory, ele, "Key", getBookCategory().toString());
216         addRow(factory, ele, "Language", getLanguage().getName());
217         return new Document(ele);
218     }
219 
220     /**
221      * @return The scope
222      */
223     public VerseKey getScope() {
224         // The following method is only available for Sword books
225         throw new UnsupportedOperationException();
226     }
227 
228     private void addRow(OSISUtil.OSISFactory factory, Element table, String key, String value) {
229         if (value == null) {
230             return;
231         }
232 
233         Element rowEle = factory.createRow();
234 
235         Element nameEle = factory.createCell();
236         Element hiEle = factory.createHI();
237         hiEle.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.HI_BOLD);
238         nameEle.addContent(hiEle);
239         Element valueElement = factory.createCell();
240         rowEle.addContent(nameEle);
241         rowEle.addContent(valueElement);
242 
243         // I18N(DMS): use name to lookup translation.
244         hiEle.addContent(key);
245 
246         String expandedValue = XMLUtil.escape(value);
247         valueElement.addContent(expandedValue);
248 
249         table.addContent(rowEle);
250     }
251 
252     private BookCategory type;
253     private String name;
254     private String initials;
255     private Map<String, String> props;
256     private static final String DEFAULT_CHARSET = "UTF-8";
257 }
258