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 - 2012
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: GBFTags.java 2221 2012-01-25 21:32:57Z dmsmith $
21   */
22  package org.crosswire.jsword.book.filter.gbf;
23  
24  import java.util.LinkedList;
25  
26  import org.crosswire.common.util.ClassUtil;
27  import org.crosswire.common.xml.XMLUtil;
28  import org.crosswire.jsword.book.Book;
29  import org.crosswire.jsword.book.DataPolice;
30  import org.crosswire.jsword.book.OSISUtil;
31  import org.crosswire.jsword.book.OSISUtil.OSISFactory;
32  import org.crosswire.jsword.passage.Key;
33  import org.crosswire.jsword.passage.NoSuchKeyException;
34  import org.crosswire.jsword.passage.Passage;
35  import org.jdom.Content;
36  import org.jdom.Element;
37  import org.jdom.Text;
38  
39  /**
40   * A holder of all of the GBF Tag Handler classes.
41   * 
42   * @see gnu.lgpl.License for license details.<br>
43   *      The copyright to this program is held by it's authors.
44   * @author Joe Walker [joe at eireneh dot com]
45   * @author DM Smith [dmsmith555 at yahoo dot com]
46   */
47  public final class GBFTags {
48      /**
49       * Prevent instantiation.
50       */
51      private GBFTags() {
52      }
53  
54      /**
55       *
56       */
57      public static final class DefaultEndTag extends AbstractTag {
58          /**
59           * @param name
60           */
61          public DefaultEndTag(String name) {
62              super(name);
63          }
64  
65          public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
66              if (stack.isEmpty()) {
67                  DataPolice.report(book, key, "Ignoring end tag without corresponding start tag: " + getName());
68                  return;
69              }
70              stack.removeFirst();
71          }
72      }
73  
74      /**
75       *
76       */
77      public static final class BoldStartTag extends AbstractTag {
78          /**
79           * @param name
80           */
81          public BoldStartTag(String name) {
82              super(name);
83          }
84  
85          public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
86              Element ele = OSIS_FACTORY.createHI();
87              ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.HI_BOLD);
88              GBFTags.updateOsisStack(book, key, stack, ele);
89          }
90      }
91  
92      /**
93       *
94       */
95      public static final class CrossRefStartTag extends AbstractTag {
96          public CrossRefStartTag(String name) {
97              super(name);
98          }
99  
100         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
101             Element ele = OSIS_FACTORY.createReference();
102 
103             String refstr = getName().substring(2);
104             try {
105                 Passage ref = (Passage) book.getKey(refstr);
106                 ele.setAttribute(OSISUtil.OSIS_ATTR_REF, ref.getOsisRef());
107             } catch (NoSuchKeyException ex) {
108                 DataPolice.report(book, key, "unable to parse reference: " + refstr);
109             }
110             GBFTags.updateOsisStack(book, key, stack, ele);
111         }
112     }
113 
114     /**
115      *
116      */
117     public static final class EOLTag extends AbstractTag {
118         /**
119          * @param name
120          */
121         public EOLTag(String name) {
122             super(name);
123         }
124 
125         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
126 
127             Element p = OSIS_FACTORY.createLB();
128             if (stack.isEmpty()) {
129                 stack.addFirst(p);
130             } else {
131                 Content top = stack.get(0);
132                 if (top instanceof Element) {
133                     Element current = (Element) top;
134                     current.addContent(p);
135                 }
136             }
137         }
138     }
139 
140     /**
141      *
142      */
143     public static final class FootnoteStartTag extends AbstractTag {
144         /**
145          * @param name
146          */
147         public FootnoteStartTag(String name) {
148             super(name);
149         }
150 
151         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
152             Element ele = OSIS_FACTORY.createNote();
153             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.NOTETYPE_STUDY);
154             GBFTags.updateOsisStack(book, key, stack, ele);
155         }
156     }
157 
158     /**
159      *
160      */
161     public static final class FootnoteEndTag extends AbstractTag {
162         /**
163          * @param name
164          */
165         public FootnoteEndTag(String name) {
166             super(name);
167         }
168 
169         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
170             if (stack.isEmpty()) {
171                 DataPolice.report(book, key, "Ignoring end tag without corresponding start tag: " + getName());
172                 return;
173             }
174 
175             Object pop = stack.removeFirst();
176             if (!(pop instanceof Element)) {
177                 DataPolice.report(book, key, "expected to pop a Note, but found " + ClassUtil.getShortClassName(pop.getClass()));
178                 return;
179             }
180 
181             Element note = (Element) pop;
182             if (note.getContentSize() < 1) {
183                 Content top = stack.get(0);
184                 if (top instanceof Element) {
185                     Element ele = (Element) top;
186                     ele.removeContent(note);
187                 }
188             }
189         }
190     }
191 
192     /**
193      *
194      */
195     public static final class HeaderStartTag extends AbstractTag {
196         /**
197          * @param name
198          */
199         public HeaderStartTag(String name) {
200             super(name);
201         }
202 
203         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
204             GBFTags.updateOsisStack(book, key, stack, OSIS_FACTORY.createTitle());
205         }
206     }
207 
208     /**
209      *
210      */
211     public static final class IgnoredTag extends AbstractTag {
212         /**
213          * @param name
214          */
215         public IgnoredTag(String name) {
216             super(name);
217         }
218 
219         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
220         }
221     }
222 
223     /**
224      *
225      */
226     public static final class ItalicStartTag extends AbstractTag {
227         /**
228          * @param name
229          */
230         public ItalicStartTag(String name) {
231             super(name);
232         }
233 
234         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
235             Element ele = OSIS_FACTORY.createHI();
236             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.HI_ITALIC);
237             GBFTags.updateOsisStack(book, key, stack, ele);
238         }
239     }
240 
241     /**
242      *
243      */
244     public static final class JustifyRightTag extends AbstractTag {
245         /**
246          * @param name
247          */
248         public JustifyRightTag(String name) {
249             super(name);
250         }
251 
252         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
253             // LATER(joe): is seg the right thing?
254             Element ele = OSIS_FACTORY.createSeg();
255             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.SEG_JUSTIFYRIGHT);
256             GBFTags.updateOsisStack(book, key, stack, ele);
257         }
258     }
259 
260     /**
261      *
262      */
263     public static final class JustifyLeftTag extends AbstractTag {
264         /**
265          * @param name
266          */
267         public JustifyLeftTag(String name) {
268             super(name);
269         }
270 
271         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
272             Element ele = OSIS_FACTORY.createSeg();
273             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.SEG_JUSTIFYLEFT);
274             GBFTags.updateOsisStack(book, key, stack, ele);
275         }
276     }
277 
278     /**
279      *
280      */
281     public static final class OTQuoteStartTag extends AbstractTag {
282         /**
283          * @param name
284          */
285         public OTQuoteStartTag(String name) {
286             super(name);
287         }
288 
289         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
290             GBFTags.updateOsisStack(book, key, stack, OSIS_FACTORY.createQ());
291         }
292     }
293 
294     /**
295      *
296      */
297     public static final class ParagraphTag extends AbstractTag {
298         /**
299          * @param name
300          */
301         public ParagraphTag(String name) {
302             super(name);
303         }
304 
305         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
306 
307             if (stack.isEmpty()) {
308                 Element p = OSIS_FACTORY.createLB();
309                 stack.addFirst(p);
310             } else {
311                 Element p = OSIS_FACTORY.createP();
312                 Content top = stack.get(0);
313                 if (top instanceof Element) {
314                     Element current = (Element) top;
315                     current.addContent(p);
316                 }
317             }
318         }
319     }
320 
321     /**
322      *
323      */
324     public static final class PoetryStartTag extends AbstractTag {
325         /**
326          * @param name
327          */
328         public PoetryStartTag(String name) {
329             super(name);
330         }
331 
332         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
333             GBFTags.updateOsisStack(book, key, stack, OSIS_FACTORY.createLG());
334         }
335     }
336 
337     /**
338      *
339      */
340     public static final class PsalmStartTag extends AbstractTag {
341         /**
342          * @param name
343          */
344         public PsalmStartTag(String name) {
345             super(name);
346         }
347 
348         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
349             GBFTags.updateOsisStack(book, key, stack, OSIS_FACTORY.createTitle());
350         }
351     }
352 
353     /**
354      *
355      */
356     public static final class RedLetterStartTag extends AbstractTag {
357         /**
358          * @param name
359          */
360         public RedLetterStartTag(String name) {
361             super(name);
362         }
363 
364         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
365             Element ele = OSIS_FACTORY.createQ();
366             ele.setAttribute(OSISUtil.ATTRIBUTE_Q_WHO, "Jesus");
367             GBFTags.updateOsisStack(book, key, stack, ele);
368         }
369     }
370 
371     /**
372      *
373      */
374     public static final class StrongsMorphTag extends AbstractTag {
375         public StrongsMorphTag(String name) {
376             super(name);
377         }
378 
379         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
380             String name = getName().trim();
381 
382             Content top = stack.get(0);
383             if (top instanceof Element) {
384                 Element ele = (Element) top;
385                 int size = ele.getContentSize();
386                 if (size == 0) {
387                     DataPolice.report(book, key, "No content to attach word to: <" + name + ">.");
388                     return;
389                 }
390 
391                 int lastIndex = size - 1;
392                 Content prevObj = ele.getContent(lastIndex);
393                 Element word = null;
394 
395                 if (prevObj instanceof Text) {
396                     word = OSIS_FACTORY.createW();
397                     ele.removeContent(prevObj);
398                     word.addContent(prevObj);
399                     ele.addContent(word);
400                 } else if (prevObj instanceof Element) {
401                     word = (Element) prevObj;
402                 } else {
403                     DataPolice.report(book, key, "No words to attach word to: <" + name + ">.");
404                     return;
405                 }
406 
407                 String existingMorph = word.getAttributeValue(OSISUtil.ATTRIBUTE_W_MORPH);
408                 StringBuilder newMorph = new StringBuilder();
409 
410                 if (existingMorph != null && existingMorph.length() > 0) {
411                     newMorph.append(existingMorph).append('|');
412                 }
413                 newMorph.append(OSISUtil.MORPH_STRONGS).append(name.substring(2));
414                 word.setAttribute(OSISUtil.ATTRIBUTE_W_MORPH, newMorph.toString());
415             }
416         }
417     }
418 
419     /**
420      *
421      */
422     public static final class StrongsWordTag extends AbstractTag {
423         /**
424          * @param name
425          */
426         public StrongsWordTag(String name) {
427             super(name);
428         }
429 
430         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
431             String name = getName().trim();
432 
433             Content top = stack.get(0);
434             if (top instanceof Element) {
435                 Element ele = (Element) top;
436                 int size = ele.getContentSize();
437                 if (size == 0) {
438                     DataPolice.report(book, key, "No content to attach word to: <" + name + ">.");
439                     return;
440                 }
441 
442                 int lastIndex = size - 1;
443                 Content prevObj = ele.getContent(lastIndex);
444                 Element word = null;
445 
446                 if (prevObj instanceof Text) {
447                     Text textItem = (Text) prevObj;
448                     word = OSIS_FACTORY.createW();
449                     ele.removeContent(textItem);
450                     word.addContent(textItem);
451                     ele.addContent(word);
452                 } else if (prevObj instanceof Element) {
453                     word = (Element) prevObj;
454                 } else {
455                     DataPolice.report(book, key, "No words to attach word to: <" + name + ">.");
456                     return;
457                 }
458 
459                 String existingLemma = word.getAttributeValue(OSISUtil.ATTRIBUTE_W_LEMMA);
460                 StringBuilder newLemma = new StringBuilder();
461 
462                 // Strong's numbers are separated by spaces w/in the attribute
463                 if (existingLemma != null && existingLemma.length() > 0) {
464                     newLemma.append(existingLemma).append(' ');
465                 }
466 
467                 // Grab the G or H and the number that follows
468                 newLemma.append(OSISUtil.LEMMA_STRONGS).append(name.substring(1));
469                 word.setAttribute(OSISUtil.ATTRIBUTE_W_LEMMA, newLemma.toString());
470             }
471         }
472     }
473 
474     /**
475      *
476      */
477     public static final class TextFootnoteTag extends AbstractTag {
478         /**
479          * @param name
480          */
481         public TextFootnoteTag(String name) {
482             super(name);
483         }
484 
485         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
486             Element ele = OSIS_FACTORY.createNote();
487             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.NOTETYPE_STUDY);
488             GBFTags.updateOsisStack(book, key, stack, ele);
489         }
490     }
491 
492     /**
493      *
494      */
495     public static final class TextTag extends AbstractTag {
496         /**
497          * @param name
498          */
499         public TextTag(String name) {
500             super(name);
501         }
502 
503         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
504             // Make sure that characters that XML requires to be escaped are.
505             String text = XMLUtil.escape(getName());
506             if (stack.isEmpty()) {
507                 stack.addFirst(new Text(text));
508             } else {
509                 Content top = stack.get(0);
510                 if (top instanceof Element) {
511                     Element ele = (Element) top;
512                     ele.addContent(text);
513                 }
514             }
515         }
516     }
517 
518     /**
519      *
520      */
521     public static final class TitleStartTag extends AbstractTag {
522         /**
523          * @param name
524          */
525         public TitleStartTag(String name) {
526             super(name);
527         }
528 
529         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
530             GBFTags.updateOsisStack(book, key, stack, OSIS_FACTORY.createTitle());
531         }
532     }
533 
534     /**
535      *
536      */
537     public static final class UnderlineStartTag extends AbstractTag {
538         /**
539          * @param name
540          */
541         public UnderlineStartTag(String name) {
542             super(name);
543         }
544 
545         public void updateOsisStack(Book book, Key key, LinkedList<Content> stack) {
546             Element ele = OSIS_FACTORY.createHI();
547             ele.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.HI_UNDERLINE);
548             GBFTags.updateOsisStack(book, key, stack, ele);
549         }
550     }
551 
552     /* private */static void updateOsisStack(Book book, Key key, LinkedList<Content> stack, Content content) {
553         Content top = stack.get(0);
554         if (top instanceof Element) {
555             Element current = (Element) top;
556             current.addContent(content);
557             stack.addFirst(content);
558         }
559     }
560 
561     /**
562      * To create OSIS DOM nodes.
563      */
564     static final OSISFactory OSIS_FACTORY = OSISUtil.factory();
565 }
566