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 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * 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
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: ReadingsBook.java 2223 2012-01-26 21:28:02Z dmsmith $
21   */
22  package org.crosswire.jsword.book.readings;
23  
24  import java.util.ArrayList;
25  import java.util.Date;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.MissingResourceException;
31  import java.util.ResourceBundle;
32  import java.util.TreeMap;
33  
34  import org.crosswire.common.util.CWClassLoader;
35  import org.crosswire.common.util.Language;
36  import org.crosswire.common.util.Logger;
37  import org.crosswire.jsword.JSMsg;
38  import org.crosswire.jsword.JSOtherMsg;
39  import org.crosswire.jsword.book.BookCategory;
40  import org.crosswire.jsword.book.BookException;
41  import org.crosswire.jsword.book.FeatureType;
42  import org.crosswire.jsword.book.OSISUtil;
43  import org.crosswire.jsword.book.basic.AbstractBook;
44  import org.crosswire.jsword.book.basic.DefaultBookMetaData;
45  import org.crosswire.jsword.passage.DefaultKeyList;
46  import org.crosswire.jsword.passage.Key;
47  import org.crosswire.jsword.passage.NoSuchKeyException;
48  import org.crosswire.jsword.passage.Passage;
49  import org.crosswire.jsword.passage.PassageKeyFactory;
50  import org.crosswire.jsword.passage.PreferredKey;
51  import org.crosswire.jsword.passage.RestrictionType;
52  import org.crosswire.jsword.passage.SetKeyList;
53  import org.crosswire.jsword.versification.system.Versifications;
54  import org.jdom.Content;
55  import org.jdom.Element;
56  
57  /**
58   * A Dictionary that displays daily Readings.
59   * 
60   * @see gnu.lgpl.License for license details.<br>
61   *      The copyright to this program is held by it's authors.
62   * @author Joe Walker [joe at eireneh dot com]
63   */
64  public class ReadingsBook extends AbstractBook implements PreferredKey {
65      /**
66       * Constructor for ReadingsBook.
67       */
68      public ReadingsBook(ReadingsBookDriver driver, String setname, BookCategory type) {
69          super(null); // set the book metadata later
70  
71          hash = new TreeMap<Key, String>();
72  
73          Locale defaultLocale = Locale.getDefault();
74          ResourceBundle prop = ResourceBundle.getBundle(setname, defaultLocale, CWClassLoader.instance(ReadingsBookDriver.class));
75  
76          // TRANSLATOR: The default name for JSword's Reading plan.
77          String name = JSMsg.gettext("Readings");
78          try {
79              name = prop.getString("title");
80          } catch (MissingResourceException e) {
81              log.warn("Missing resource: 'title' while parsing: " + setname);
82          }
83  
84          DefaultBookMetaData bmd = new DefaultBookMetaData(driver, name, type);
85          bmd.setInitials(setname);
86          bmd.setLanguage(new Language(Locale.getDefault().getLanguage()));
87          setBookMetaData(bmd);
88  
89          // Go through the current year
90          java.util.Calendar greg = new java.util.GregorianCalendar();
91          greg.set(java.util.Calendar.DAY_OF_MONTH, 1);
92          greg.set(java.util.Calendar.MONDAY, java.util.Calendar.JANUARY);
93          int currentYear = greg.get(java.util.Calendar.YEAR);
94  
95          while (greg.get(java.util.Calendar.YEAR) == currentYear) {
96              String internalKey = ReadingsKey.external2internal(greg);
97              String readings = "";
98  
99              try {
100                 readings = prop.getString(internalKey);
101                 hash.put(new ReadingsKey(greg.getTime()), readings);
102             } catch (MissingResourceException e) {
103                 log.warn("Missing resource: " + internalKey + " while parsing: " + setname);
104             }
105 
106             greg.add(java.util.Calendar.DATE, 1);
107         }
108 
109         global = new SetKeyList(hash.keySet(), getName());
110     }
111 
112     /* (non-Javadoc)
113      * @see org.crosswire.jsword.passage.PreferredKey#getPreferred()
114      */
115     public Key getPreferred() {
116         return new ReadingsKey(new Date());
117     }
118 
119     public Iterator<Content> getOsisIterator(Key key, boolean allowEmpty) throws BookException {
120         if (!(key instanceof ReadingsKey)) {
121             // TRANSLATOR: Error condition: Indicates that something could not be found in the book. {0} is a placeholder for the unknown key.
122             throw new BookException(JSMsg.gettext("Key not found {0}", key.getName()));
123         }
124 
125         // TODO(DMS): make the iterator be demand driven
126         List<Content> content = new ArrayList<Content>();
127 
128         Element title = OSISUtil.factory().createTitle();
129         title.addContent(key.getName());
130         content.add(title);
131 
132         String readings = hash.get(key);
133         if (readings == null) {
134             // TRANSLATOR: Error condition: Indicates that something could not be found in the book. {0} is a placeholder for the unknown key.
135             throw new BookException(JSMsg.gettext("Key not found {0}", key.getName()));
136         }
137 
138         try {
139             // AV11N(DMS): Is this right?
140             PassageKeyFactory keyf = PassageKeyFactory.instance();
141             Passage ref = (Passage) keyf.getKey(Versifications.instance().getDefaultVersification(), readings);
142 
143             Element list = OSISUtil.factory().createList();
144             content.add(list);
145 
146             Iterator<Key> it = ref.rangeIterator(RestrictionType.NONE);
147             while (it.hasNext()) {
148                 Key range = it.next();
149 
150                 Element reading = OSISUtil.factory().createReference();
151                 reading.setAttribute(OSISUtil.OSIS_ATTR_REF, range.getOsisRef());
152                 reading.addContent(range.getName());
153 
154                 Element item = OSISUtil.factory().createItem();
155                 item.addContent(reading);
156                 list.addContent(item);
157             }
158         } catch (NoSuchKeyException ex) {
159             content.add(OSISUtil.factory().createText(JSOtherMsg.lookupText("Failed to parse {0}", readings)));
160         }
161 
162         return content.iterator();
163     }
164 
165     /* (non-Javadoc)
166      * @see org.crosswire.jsword.book.Book#contains(org.crosswire.jsword.passage.Key)
167      */
168     public boolean contains(Key key) {
169         return false;
170     }
171 
172     /* (non-Javadoc)
173      * @see org.crosswire.jsword.book.Book#getRawText(org.crosswire.jsword.passage.Key)
174      */
175     public String getRawText(Key key) throws BookException {
176         return "";
177     }
178 
179     /* (non-Javadoc)
180      * @see org.crosswire.jsword.book.Book#isWritable()
181      */
182     public boolean isWritable() {
183         return false;
184     }
185 
186     /* (non-Javadoc)
187      * @see org.crosswire.jsword.book.Book#setRawText(org.crosswire.jsword.passage.Key, java.lang.String)
188      */
189     public void setRawText(Key key, String rawData) throws BookException {
190         throw new BookException(JSOtherMsg.lookupText("This Book is read-only."));
191     }
192 
193     /* (non-Javadoc)
194      * @see org.crosswire.jsword.book.Book#setAliasKey(org.crosswire.jsword.passage.Key, org.crosswire.jsword.passage.Key)
195      */
196     public void setAliasKey(Key alias, Key source) throws BookException {
197         throw new BookException(JSOtherMsg.lookupText("This Book is read-only."));
198     }
199 
200     /* (non-Javadoc)
201      * @see org.crosswire.jsword.book.Book#getValidKey(java.lang.String)
202      */
203     public Key getValidKey(String name) {
204         try {
205             return getKey(name);
206         } catch (NoSuchKeyException e) {
207             return createEmptyKeyList();
208         }
209     }
210 
211     /* (non-Javadoc)
212      * @see org.crosswire.jsword.book.Book#getKey(java.lang.String)
213      */
214     public Key getKey(String name) throws NoSuchKeyException {
215         DefaultKeyList reply = new DefaultKeyList();
216         reply.addAll(new ReadingsKey(name, name, global));
217         return reply;
218     }
219 
220     /* (non-Javadoc)
221      * @see org.crosswire.jsword.book.Book#getGlobalKeyList()
222      */
223     public Key getGlobalKeyList() {
224         return global;
225     }
226 
227     /* (non-Javadoc)
228      * @see org.crosswire.jsword.book.Book#createEmptyKeyList()
229      */
230     public Key createEmptyKeyList() {
231         return new DefaultKeyList();
232     }
233 
234     @Override
235     public boolean hasFeature(FeatureType feature) {
236         return feature == FeatureType.DAILY_DEVOTIONS;
237     }
238 
239     /**
240      * The global key list
241      */
242     private Key global;
243 
244     /**
245      * The store of keys and data
246      */
247     private Map<Key, String> hash;
248 
249     /**
250      * The log stream
251      */
252     private static final Logger log = Logger.getLogger(ReadingsBook.class);
253 }
254