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