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;
21  
22  import java.util.Iterator;
23  import java.util.Set;
24  
25  import org.crosswire.common.activate.Activatable;
26  import org.crosswire.common.util.Language;
27  import org.crosswire.jsword.index.IndexStatus;
28  import org.crosswire.jsword.index.IndexStatusListener;
29  import org.crosswire.jsword.index.search.SearchRequest;
30  import org.crosswire.jsword.passage.Key;
31  import org.crosswire.jsword.passage.NoSuchKeyException;
32  import org.jdom2.Content;
33  import org.jdom2.Document;
34  
35  /**
36   * Book is the most basic store of textual data - It can retrieve data either as
37   * an XML document or as plain text - It uses Keys to refer to parts of itself,
38   * and can search for words (returning Keys).
39   * 
40   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
41   * @author Joe Walker
42   */
43  public interface Book extends Activatable, Comparable<Book> {
44      /**
45       * Get a complete list of index entries. Create a Key that encompasses all
46       * of the known valid keys for the given context. For a dictionary this will
47       * include all of the entries in the dictionary, for a Bible this will
48       * probably include all the verses in the Bible, but a commentary may well
49       * miss some out.
50       * 
51       * @return A Key that includes all of the known Keys
52       */
53      Key getGlobalKeyList();
54  
55      /**
56       * Get a complete list of entries. Create a Key that encompasses all
57       * of the existing entries in the book. For most modules this will be the
58       * same as {@link #getGlobalKeyList}, however for a Bible, it will
59       * get the references that are actually in the book.
60       * 
61       * @return A Key that includes all of the existing Keys
62       */
63      Key getScope();
64  
65      /**
66       * Get a Key for the name, if possible. Otherwise return an empty Key.
67       * 
68       * @param name
69       *            The string to translate into a Key
70       * @return a valid key.
71       */
72      Key getValidKey(String name);
73  
74      /**
75       * Someone has typed in a reference to find, but we need a Key to actually
76       * look it up. So we create a Key from the string if such a translation is
77       * possible. The returned Key may be a BranchKey if the string represents
78       * more than one Key.
79       * 
80       * @param name
81       *            The string to translate into a Key
82       * @return The Key corresponding to the input text
83       * @throws NoSuchKeyException
84       *             If the name can not be parsed.
85       */
86      Key getKey(String name) throws NoSuchKeyException;
87  
88      /**
89       * Fetch an empty Key to which we can add Keys. Not all implementations of
90       * Key are able to hold any type of Key, It isn't reasonable to expect a Key
91       * of Bible verses (=Passage) to hold a dictionary Key. So each KeyFactory
92       * must be able to create you an empty Key to which you can safely add other
93       * Keys it generates.
94       * 
95       * @return An empty Key that can hold other Keys from this factory.
96       */
97      Key createEmptyKeyList();
98  
99      /**
100      * Meta-Information: What version of the Bible is this?
101      * 
102      * @return A Version for this Bible
103      */
104     BookMetaData getBookMetaData();
105 
106     /**
107      * Set the meta-information for this book.
108      * 
109      * @param bmd the BookMetaData that describes this book.
110      */
111     void setBookMetaData(BookMetaData bmd);
112 
113     /**
114      * Return an iterator that returns each key's OSIS in turn.
115      * 
116      * @param key
117      *            the Items to locate
118      * @param allowEmpty
119      *            indicates whether empty keys should be present.
120      * @param allowGenTitles
121      *            indicates whether to generate titles
122      * @return an iterator over the OSIS Content
123      * @throws BookException
124      *             If anything goes wrong with this method
125      */
126     Iterator<Content> getOsisIterator(Key key, boolean allowEmpty, boolean allowGenTitles) throws BookException;
127 
128     /**
129      * Returns <tt>true</tt> if this book contains the specified element.
130      * 
131      * @param key
132      *            element whose presence in this book is to be tested.
133      * @return <tt>true</tt> if this book contains the specified element.
134      */
135     boolean contains(Key key);
136 
137     /**
138      * Returns the raw text that getData(Key key) builds into OSIS.
139      * 
140      * @param key
141      *            The item to locate
142      * @return The found Book data
143      * @throws BookException
144      *             If anything goes wrong with this method
145      */
146     String getRawText(Key key) throws BookException;
147 
148     /**
149      * A Book is writable if the file system allows the underlying files to be
150      * opened for writing and if the driver for the book allows writing.
151      * Ultimately, all drivers should allow writing. At this time writing is not
152      * supported by drivers, so abstract implementations should return false and
153      * let specific implementations return true otherwise.
154      * 
155      * @return true if the book is writable
156      */
157     boolean isWritable();
158 
159     /**
160      * Store the raw text for the given key. This will replace/hide any raw text
161      * that already is present. Note: it is the responsibility of the calling
162      * program to ensure that the raw text matches the character set encoding
163      * and markup of the module.
164      * 
165      * @param key
166      *            The item to locate
167      * @param rawData
168      *            The text to store
169      * @throws BookException
170      *             If anything goes wrong with this method
171      */
172     void setRawText(Key key, String rawData) throws BookException;
173 
174     /**
175      * Store an alias of one key to another. Some Bibles do not have a verse by
176      * verse numbering system but rather meld several verses into one. Thus, any
177      * verse in the range refers to the same verse. Also it may apply to
178      * biblical commentaries that are indexed by Book, Chapter, Verse and that
179      * discuss the Bible at a verse range level. For a dictionary, it may be
180      * used for synonyms.
181      * <p>
182      * It should be an exception to set an alias when that alias already has raw
183      * text. Also, it should be an exception to set an alias to an alias.
184      * However, getRawText(Key) must be able to handle alias chains.
185      * </p>
186      * 
187      * @param alias
188      *            the key that aliases another
189      * @param source
190      *            the key that holds the text
191      * @throws BookException
192      *             If anything goes wrong with this method
193      */
194     void setAliasKey(Key alias, Key source) throws BookException;
195 
196     /**
197      * Retrieval: For a given search spec find a list of references to it. If
198      * there are no matches then null should be returned, otherwise a valid Key.
199      * 
200      * @param request
201      *            The search spec.
202      * @return the key that matches the search or null
203      * @throws BookException
204      *             If anything goes wrong with this method
205      */
206     Key find(SearchRequest request) throws BookException;
207 
208     /**
209      * Retrieval: For a given search spec find a list of references to it. If
210      * there are no matches then null should be returned, otherwise a valid Key.
211      * 
212      * @param request
213      *            The search spec.
214      * @return the key that matches the search or null
215      * @throws BookException
216      *             If anything goes wrong with this method
217      */
218     Key find(String request) throws BookException;
219 
220     /**
221      * The name of the book, for example "King James Version" or
222      * "Bible in Basic English" or "Greek". In general it should be possible to
223      * deduce the initials from the name by removing all the non-capital
224      * letters. Although this is only a generalization. This method should not
225      * return null or a blank string.
226      * 
227      * @return The name of this book
228      */
229     String getName();
230 
231     /**
232      * What category of content is this, a Bible or a reference work like a
233      * Dictionary or Commentary.
234      * 
235      * @return The category of book
236      */
237     BookCategory getBookCategory();
238 
239     /**
240      * Accessor for the driver that runs this Book. Note this method should only
241      * be used to delete() Books. Everything else you should want to do to a
242      * Book should be available in other ways.
243      * 
244      * @return the book's driver
245      */
246     BookDriver getDriver();
247 
248     /**
249      * The language of the book.
250      * 
251      * @return the common name for the language
252      */
253     Language getLanguage();
254 
255     /**
256      * The abbreviation of this book - how people familiar with this book will know
257      * it, for example "NIV", "KJV".
258      * 
259      * @return The book's initials
260      */
261     String getAbbreviation();
262 
263     /**
264      * The internal name of this book.
265      * 
266      * @return The book's internal name
267      */
268     String getInitials();
269 
270     /**
271      * Calculated field: Get an OSIS identifier for the OsisText.setOsisIDWork()
272      * and the Work.setOsisWork() methods. The response will generally be of the
273      * form [Bible][Dict..].getInitials
274      * 
275      * @return The OSIS id of this book
276      */
277     String getOsisID();
278 
279     /**
280      * Return the likelihood that we have a match. This allows for calling the
281      * book different things and still be found.
282      * 
283      * @param name one of many ways to name this book.
284      * @return true if we have a match.
285      */
286     boolean match(String name);
287 
288     /**
289      * Indicate whether this book is supported by JSword. Since the expectation
290      * is that all books are supported, abstract implementations should return
291      * true and let specific implementations return false if they cannot support
292      * the book.
293      * 
294      * @return true if the book is supported
295      */
296     boolean isSupported();
297 
298     /**
299      * Indicate whether this book is enciphered. Since the expectation is that
300      * most books are unenciphered, abstract implementations should return false
301      * and let specific implementations return true otherwise.
302      * 
303      * @return true if the book is enciphered
304      */
305     boolean isEnciphered();
306 
307     /**
308      * Indicate whether this book is enciphered and without a key. Since the
309      * expectation is that most books are not encrypted, abstract implementations
310      * should return false and let specific implementations return true
311      * otherwise.
312      * 
313      * @return true if the book is locked
314      */
315     boolean isLocked();
316 
317     /**
318      * Unlocks a book with the given key.
319      * 
320      * @param unlockKey
321      *            the key to try
322      * @return true if the unlock key worked.
323      */
324     boolean unlock(String unlockKey);
325 
326     /**
327      * Gets the unlock key for the module.
328      * 
329      * @return the unlock key, if any, null otherwise.
330      */
331     String getUnlockKey();
332 
333     /**
334      * Indicate whether this book is questionable. A book may be deemed
335      * questionable if it's quality or content has not been confirmed. Since the
336      * expectation is that all books are not questionable, abstract
337      * implementations should return false and let specific implementations
338      * return true if the book is questionable.
339      * 
340      * @return true if the book is questionable
341      */
342     boolean isQuestionable();
343 
344     /**
345      * Calculated field: The name of the name, which could be helpful to
346      * distinguish similar Books available through 2 BookDrivers.
347      * 
348      * @return The driver name
349      */
350     String getDriverName();
351 
352     /**
353      * Return the orientation of the script of the Book. If a book contains more
354      * than one script, it refers to the dominate script of the book. This will
355      * be used to present Arabic and Hebrew in their proper orientation. Note:
356      * some languages have multiple scripts which don't have the same
357      * directionality.
358      * 
359      * @return true if the orientation for the dominate script is LeftToRight.
360      */
361     boolean isLeftToRight();
362 
363     /**
364      * Return whether the feature is supported by the book.
365      * 
366      * @param feature the type of the Feature to check
367      * @return whether the feature is supported
368      */
369     boolean hasFeature(FeatureType feature);
370 
371     /**
372      * Get a list of all the properties available to do with this Book. The
373      * returned Properties will be read-only so any attempts to alter it will
374      * fail.
375      * 
376      * @return the read-only properties for this book.
377      */
378     Set<String> getPropertyKeys();
379 
380     /**
381      * Retrieve a single property for this book.
382      * 
383      * @param key
384      *            the key of the property.
385      * @return the value of the property
386      */
387     String getProperty(String key);
388 
389     /**
390      * Set a property for this book.
391      * 
392      * @param key
393      *            the key of the property.
394      * @param value
395      *            the value of the property
396      */
397     void putProperty(String key, String value);
398 
399     /**
400      * Saves an entry to a particular configuration file.
401      * 
402      * @param key the entry that we are saving
403      * @param value the value of the entry
404      * @param forFrontend when {@code true} save to front end storage, else in shared storage
405      */
406     void putProperty(String key, String value, boolean forFrontend);
407 
408     /**
409      * Has anyone generated a search index for this Book?
410      * 
411      * @return the status of the index for this book.
412      * @see org.crosswire.jsword.index.IndexManager
413      */
414     IndexStatus getIndexStatus();
415 
416     /**
417      * This method does not alter the index status, however it is for Indexers
418      * that are responsible for indexing and have changed the status themselves.
419      * 
420      * @param status the status to set for this book
421      * @see org.crosswire.jsword.index.IndexManager
422      */
423     void setIndexStatus(IndexStatus status);
424 
425     /**
426      * Get an OSIS representation of information concerning this Book.
427      * 
428      * @return information for this book represented as OSIS
429      */
430     Document toOSIS();
431 
432     /**
433      * Adds a <code>IndexStatusListener</code> to the listener list.
434      * <p>
435      * A <code>IndexStatusEvent</code> will get fired in response to
436      * <code>setIndexStatus</code>.
437      * 
438      * @param li
439      *            the <code>IndexStatusListener</code> to be added
440      */
441     void addIndexStatusListener(IndexStatusListener li);
442 
443     /**
444      * Removes a <code>IndexStatusListener</code> from the listener list.
445      * 
446      * @param li
447      *            the <code>IndexStatusListener</code> to be removed
448      */
449     void removeIndexStatusListener(IndexStatusListener li);
450 }
451