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: ConfigEntryType.java 2223 2012-01-26 21:28:02Z dmsmith $
21   */
22  package org.crosswire.jsword.book.sword;
23  
24  import java.util.regex.Pattern;
25  
26  import org.crosswire.common.util.Language;
27  import org.crosswire.common.util.Version;
28  import org.crosswire.jsword.book.BookCategory;
29  
30  /**
31   * Constants for the keys in a Sword Config file. Taken from
32   * http://sword.sourceforge.net/cgi-bin/twiki/view/Swordapi/ConfFileLayout<br/>
33   * now located at
34   * http://www.crosswire.org/ucgi-bin/twiki/view/Swordapi/ConfFileLayout<br/>
35   * now located at http://www.crosswire.org/wiki/index.php/DevTools:Modules<br/>
36   * now located at http://www.crosswire.org/wiki/DevTools:confFiles<br/>
37   * <p>
38   * Note: This file is organized the same as the latest wiki documentation.
39   * 
40   * @see gnu.lgpl.License for license details.<br>
41   *      The copyright to this program is held by it's authors.
42   * @author Joe Walker [joe at eireneh dot com]
43   * @author DM Smith [dmsmith555 at yahoo dot com]
44   */
45  public enum ConfigEntryType {
46      /**
47       * The abbreviated name by which this book is known. This is in the [] on
48       * the first non-blank line of the conf. JSword uses this for display and
49       * access purposes.
50       */
51      INITIALS("Initials") {
52          @Override
53          public boolean isSynthetic() {
54              return true;
55          }
56      },
57  
58      /**
59       * Relative path to the data files, some issues with this
60       */
61      DATA_PATH("DataPath") {
62          @Override
63          public boolean isAllowed(String value) {
64              return true;
65          }
66      },
67  
68      /**
69       * The full name of this book
70       */
71      DESCRIPTION("Description"),
72  
73      /**
74       * This indicates how the book was stored.
75       */
76      MOD_DRV("ModDrv", -1,
77          "RawText",
78          "zText",
79          "RawCom",
80          "RawCom4",
81          "zCom",
82          "HREFCom",
83          "RawFiles",
84          "RawLD",
85          "RawLD4",
86          "zLD",
87          "RawGenBook"
88      ),
89  
90      /**
91       * The type of compression in use. While LZSS is the default, it is not used.
92       * At least so far.
93       */
94      COMPRESS_TYPE("CompressType", 0,
95          "LZSS",
96          "ZIP"
97      ),
98  
99      /**
100      * The level at which compression is applied, BOOK, CHAPTER, or VERSE
101      */
102     BLOCK_TYPE("BlockType", 1,
103         "BOOK",
104         "CHAPTER",
105         "VERSE"
106     ),
107 
108     /**
109      * single value integer, unknown use, some indications that we ought to be
110      * using it
111      */
112     BLOCK_COUNT("BlockCount", "200") {
113         @Override
114         public boolean isAllowed(String aValue) {
115             try {
116                 Integer.parseInt(aValue);
117                 return true;
118             } catch (NumberFormatException e) {
119                 return false;
120             }
121         }
122 
123         @Override
124         public Object convert(String input) {
125             try {
126                 return Integer.valueOf(input);
127             } catch (NumberFormatException e) {
128                 return getDefault();
129             }
130         }
131     },
132 
133     /**
134      * The kind of key that a Generic Book uses.
135      */
136     KEY_TYPE("KeyType", 0,
137         "TreeKey",
138         "VerseKey"
139     ),
140 
141     /**
142      * If this exists in the conf, then the book is encrypted. The value is used
143      * to unlock the book. The encryption algorithm is Sapphire.
144      */
145     CIPHER_KEY("CipherKey"),
146 
147     /**
148      * This indicates the versification of the book, with KJV being the default.
149      */
150     VERSIFICATION("Versification", 3,
151         "Catholic",
152         "Catholic2",
153         "German",
154         "KJV",
155         "KJVA",
156         "Leningrad",
157         "Luther",
158         "MT",
159         "NRSV",
160         "NRSVA",
161         "Synodal",
162         "SynodalP",
163         "Vulg"
164     ),
165 
166     /**
167      * Global Option Filters are the names of routines in SWORD that can be used
168      * to display the data. These are not used by JSword.
169      */
170     GLOBAL_OPTION_FILTER("GlobalOptionFilter", -1,
171         "GBFStrongs",
172         "GBFFootnotes",
173         "GBFMorph",
174         "GBFHeadings",
175         "GBFRedLetterWords",
176         "GBFScripref", // no longer in wiki
177         "ThMLStrongs",
178         "ThMLFootnotes",
179         "ThMLScripref",
180         "ThMLMorph",
181         "ThMLHeadings",
182         "ThMLVariants",
183         "ThMLLemma",
184         "UTF8Cantillation",
185         "UTF8GreekAccents",
186         "UTF8HebrewPoints",
187         "OSISStrongs",
188         "OSISFootnotes",
189         "OSISScripref",
190         "OSISMorph",
191         "OSISHeadings",
192         "OSISVariants",
193         "OSISRedLetterWords",
194         "OSISLemma",
195         "OSISRuby"
196     )
197     {
198         @Override
199         public boolean mayRepeat() {
200             return true;
201         }
202     },
203 
204     /**
205      * The layout direction of the text in the book. Hebrew, Arabic and Farsi
206      * RtoL. Most are 'LtoR'. Some are 'bidi', bi-directional. E.g.
207      * hebrew-english glossary.
208      */
209     DIRECTION("Direction", 0,
210         "LtoR",
211         "RtoL",
212         "bidi"
213     ),
214 
215     /**
216      * This indicates the kind of markup used for the book.
217      */
218     SOURCE_TYPE("SourceType", 0,
219         "Plaintext",
220         "GBF",
221         "ThML",
222         "OSIS",
223         "TEI"
224     ),
225 
226     /**
227      * The character encoding. Only Latin-1 and UTF-8 are supported.
228      */
229     ENCODING("Encoding", 0,
230         "Latin-1",
231         "UTF-8"
232     ),
233 
234     /**
235      * Display level is used by GenBooks to do auto expansion in the tree. A
236      * level of 2 indicates that the first two levels should be shown.
237      */
238     DISPLAY_LEVEL("DisplayLevel", "1") {
239         @Override
240         public boolean isAllowed(String value) {
241             try {
242                 Integer.parseInt(value);
243                 return true;
244             } catch (NumberFormatException e) {
245                 return false;
246             }
247         }
248 
249         @Override
250         public Object convert(String input) {
251             try {
252                 return Integer.valueOf(input);
253             } catch (NumberFormatException e) {
254                 return null;
255             }
256         }
257     },
258 
259     /**
260      * A recommended font to use for the book.
261      */
262     FONT("Font"),
263 
264     /**
265      * When false do not show quotation marks for OSIS text that has <q>
266      * elements.
267      */
268     OSIS_Q_TO_TICK("OSISqToTick", 0,
269         "true",
270         "false"
271     )
272     {
273         @Override
274         public Object convert(String input) {
275             return Boolean.valueOf(input);
276         }
277     },
278 
279     /**
280      * A Feature describes a characteristic of the Book.
281      */
282     FEATURE("Feature", -1,
283         "StrongsNumbers",
284         "GreekDef",
285         "HebrewDef",
286         "GreekParse",
287         "HebrewParse",
288         "DailyDevotion",
289         "Glossary",
290         "Images"
291     )
292     {
293         @Override
294         public boolean mayRepeat() {
295             return true;
296         }
297     },
298 
299     /**
300      * Books with a Feature of Glossary are used to map words FROM one language
301      * TO another.
302      */
303     GLOSSARY_FROM("GlossaryFrom") {
304         @Override
305         public Object convert(String input) {
306             return new Language(input);
307         }
308 
309         @Override
310         public String unconvert(Object internal) {
311             if (internal instanceof Language) {
312                 return ((Language) internal).getCode();
313             }
314             return super.unconvert(internal);
315         }
316     },
317 
318     /**
319      * Books with a Feature of Glossary are used to map words FROM one language
320      * TO another.
321      */
322     GLOSSARY_TO("GlossaryTo") {
323         @Override
324         public Object convert(String input) {
325             return new Language(input);
326         }
327 
328         @Override
329         public String unconvert(Object internal) {
330             if (internal instanceof Language) {
331                 return ((Language) internal).getCode();
332             }
333             return super.unconvert(internal);
334         }
335     },
336 
337     /**
338      * The short name of this book.
339      */
340     ABBREVIATION("Abbreviation"),
341 
342     /**
343      * Contains rtf that describes the book.
344      */
345     ABOUT("About") {
346         @Override
347         public boolean allowsContinuation() {
348             return true;
349         }
350 
351         @Override
352         public boolean allowsRTF() {
353             return true;
354         }
355     },
356 
357     /**
358      * An informational string indicating the current version of the book.
359      */
360     VERSION("Version", "1.0") {
361         @Override
362         public boolean isAllowed(String aValue) {
363             try {
364                 new Version(aValue);
365                 return true;
366             } catch (IllegalArgumentException e) {
367                 return false;
368             }
369         }
370         @Override
371         public Object convert(String input) {
372             try {
373                 return new Version(input);
374             } catch (IllegalArgumentException e) {
375                 return null;
376             }
377         }
378     },
379 
380     /**
381      * multiple values starting with History, some sort of change-log. In the
382      * conf these are of the form History_x.y. We strip off the x.y and prefix
383      * the value with it. The x.y corresponds to a current or prior Version
384      * value.
385      */
386     HISTORY("History") {
387         @Override
388         public boolean mayRepeat() {
389             return true;
390         }
391 
392         @Override
393         public boolean reportDetails() {
394             return false;
395         }
396     },
397 
398     /**
399      * single value version number, lowest sword c++ version that can read this
400      * book JSword does not use this value.
401      */
402     MINIMUM_VERSION("MinimumVersion", "1.5.1a"),
403 
404     /**
405      * The Category of the book. Used on the web to classify books into a tree.
406      */
407     CATEGORY("Category", 0,
408         "Other",
409         "Daily Devotional",
410         "Glossaries",
411         "Cults / Unorthodox / Questionable Material",
412         "Essays",
413         "Maps",
414         "Images",
415         "Biblical Texts",
416         "Commentaries",
417         "Lexicons / Dictionaries",
418         "Generic Books"
419     )
420     {
421         @Override
422         public Object convert(String input) {
423             return BookCategory.fromString(input);
424         }
425     },
426 
427     /**
428      * Library of Congress Subject Heading. Typically this is of the form
429      * BookCategory Scope Language, where scope is typically O.T., N.T.
430      */
431     LCSH("LCSH"),
432 
433     /**
434      * single value string, defaults to en, the language of the book
435      */
436     LANG("Lang", "en") {
437         @Override
438         public Object convert(String input) {
439             return new Language(input);
440         }
441 
442         @Override
443         public String unconvert(Object internal) {
444             if (internal instanceof Language) {
445                 return ((Language) internal).getCode();
446             }
447             return super.unconvert(internal);
448         }
449     },
450 
451     /**
452      * The installed size of the book in bytes. This is not the size of the zip
453      * that is downloaded.
454      */
455     INSTALL_SIZE("InstallSize") {
456         @Override
457         public boolean isAllowed(String value) {
458             try {
459                 Integer.parseInt(value);
460                 return true;
461             } catch (NumberFormatException e) {
462                 return false;
463             }
464         }
465 
466         @Override
467         public Object convert(String input) {
468             try {
469                 return Integer.valueOf(input);
470             } catch (NumberFormatException e) {
471                 return null;
472             }
473         }
474     },
475 
476     /**
477      * The date that this version of the book was last updated. Informational
478      * only.
479      */
480     SWORD_VERSION_DATE("SwordVersionDate") {
481         @Override
482         public boolean isAllowed(String value) {
483             return validDatePattern.matcher(value).matches();
484         }
485 
486         private Pattern validDatePattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
487     },
488 
489     /**
490      * A list of prior "initials" for the current book.
491      * TODO(dms): when a user installs a book with an obsoletes that matches
492      * an installed book, offer the user the opportunity to delete the old book.
493      */
494     OBSOLETES("Obsoletes") {
495         @Override
496         public boolean mayRepeat() {
497             return true;
498         }
499 
500         @Override
501         public boolean reportDetails() {
502             return false;
503         }
504     },
505 
506     /**
507      * Single value version number, lowest sword c++ version that can read this
508      * book JSword does not use this value.
509      */
510     OSIS_VERSION("OSISVersion"),
511 
512     /**
513      * Informational copyright notice.
514      */
515     COPYRIGHT("Copyright") {
516         @Override
517         public boolean allowsContinuation() {
518             return true;
519         }
520     },
521 
522     /**
523      * single value string, unknown use
524      */
525     COPYRIGHT_HOLDER("CopyrightHolder"),
526 
527     /**
528      * Copyright info. Informational only.
529      * This is a year, a year range or a comma separated list of these.
530      */
531     COPYRIGHT_DATE("CopyrightDate") {
532         @Override
533         public boolean isAllowed(String value) {
534             return validDatePattern.matcher(value).matches();
535         }
536 
537         private Pattern validDatePattern = Pattern.compile("\\d{4}(\\s*-\\s*\\d{4})?(\\s*,\\s*\\d{4}(\\s*-\\s*\\d{4})?)*");
538     },
539 
540     /**
541      * Copyright info. Informational only.
542      */
543     COPYRIGHT_NOTES("CopyrightNotes") {
544         @Override
545         public boolean allowsContinuation() {
546             return true;
547         }
548 
549         @Override
550         public boolean allowsRTF() {
551             return true;
552         }
553     },
554 
555     /**
556      * Copyright info. Informational only.
557      */
558     COPYRIGHT_CONTACT_NAME("CopyrightContactName") {
559         @Override
560         public boolean allowsContinuation() {
561             return true;
562         }
563 
564         @Override
565         public boolean allowsRTF() {
566             return true;
567         }
568     },
569 
570     /**
571      * Copyright info. Informational only.
572      */
573     COPYRIGHT_CONTACT_NOTES("CopyrightContactNotes") {
574 
575         @Override
576         public boolean allowsContinuation() {
577             return true;
578         }
579 
580         @Override
581         public boolean allowsRTF() {
582             return true;
583         }
584     },
585 
586     /**
587      * Copyright info. Informational only.
588      */
589     COPYRIGHT_CONTACT_ADDRESS("CopyrightContactAddress") {
590         @Override
591         public boolean allowsContinuation() {
592             return true;
593         }
594 
595         @Override
596         public boolean allowsRTF() {
597             return true;
598         }
599     },
600 
601     /**
602      * Copyright info. Informational only.
603      */
604     COPYRIGHT_CONTACT_EMAIL("CopyrightContactEmail"),
605 
606     /**
607      * A one line promo statement, required by Lockman for NASB
608      */
609     SHORT_PROMO("ShortPromo"),
610 
611     /**
612      * A one line copyright statement, required by Lockman for NASB
613      */
614     SHORT_COPYRIGHT("ShortCopyright"),
615 
616     /**
617      * Copyright info. Informational only.
618      */
619     DISTRIBUTION_LICENSE("DistributionLicense", 0,
620         "Public Domain",
621         "Copyrighted",
622         "Copyrighted; Free non-commercial distribution",
623         "Copyrighted; Permission to distribute granted to CrossWire",
624         "Copyrighted; Freely distributable",
625         "Copyrighted; Permission granted to distribute non-commercially in Sword format",
626         "GFDL",
627         "GPL",
628         "Creative Commons: by-nc-nd",
629         "Creative Commons: by-nc-sa",
630         "Creative Commons: by-nc",
631         "Creative Commons: by-nd",
632         "Creative Commons: by-sa",
633         "Creative Commons: by"
634     ),
635 
636     /**
637      * Copyright info. Informational only.
638      */
639     DISTRIBUTION_NOTES("DistributionNotes") {
640 
641         @Override
642         public boolean allowsContinuation() {
643             return true;
644         }
645     },
646 
647     /**
648      * Information on where the book's text was obtained.
649      */
650     TEXT_SOURCE("TextSource") {
651 
652         @Override
653         public boolean allowsContinuation() {
654             return true;
655         }
656     },
657 
658     /**
659      * Contains the URL (a bare URL, not an HTML <a> link) of a web page for unlocking instructions/payment.
660      */
661     UNLOCK_URL("UnlockURL"),
662 
663     /**
664      * Deliberately not in wiki. Similar to DataPath. It gives where on the CrossWire server the book can
665      * be found. Informational only.
666      */
667     DISTRIBUTION_SOURCE("DistributionSource") {
668 
669         @Override
670         public boolean allowsContinuation() {
671             return true;
672         }
673     },
674 
675     /**
676      * New. Not in wiki. Present in SWORD engine. Present in hesychius.conf w/ PapyriPlain
677      */
678     LOCAL_STRIP_FILTER("LocalStripFilter"),
679 
680     /**
681      * New. Not in wiki. Present in SWORD engine. Present in hesychius.conf w/ IncludeKeyInSearch
682      */
683     SEARCH_OPTION("SearchOption"),
684 
685     /**
686      * The location of a collection of modules. JSword uses this to install and
687      * delete a module.
688      */
689     LIBRARY_URL("LibraryURL") {
690         @Override
691         public boolean isSynthetic() {
692             return true;
693         }
694     },
695 
696     /**
697      * The location of the module. JSword uses this to access a module.
698      */
699     LOCATION_URL("LocationURL") {
700         @Override
701         public boolean isSynthetic() {
702             return true;
703         }
704     };
705 
706     /**
707      * Simple ctor
708      */
709     private ConfigEntryType(String name) {
710         this.name = name;
711         this.defaultValue = null;
712         this.picks = null;
713     }
714 
715     /**
716      * Simple ctor
717      */
718     private ConfigEntryType(String name, String defaultValue) {
719         this.name = name;
720         this.defaultValue = convert(defaultValue);
721         this.picks = null;
722     }
723 
724     /**
725      * Simple ctor
726      */
727     private ConfigEntryType(String name, int defaultPick, String... picks) {
728         this.name = name;
729         if (defaultPick >= 0 && defaultPick < picks.length) {
730             this.defaultValue = convert(picks[defaultPick]);
731         } else {
732             this.defaultValue = null;
733         }
734         this.picks = picks;
735     }
736 
737     /**
738      * Returns the normalized name of this ConfigEntry.
739      * 
740      * @return the name
741      */
742     public String getName() {
743         return name;
744     }
745 
746     /**
747      * Determines whether the string is allowed. For some config entries, the
748      * value is expected to be one of a group, for others the format is defined.
749      * 
750      * @param value
751      *            the string to be checked
752      * @return true if the string is allowed
753      */
754     public boolean isAllowed(String value) {
755         if (hasChoices()) {
756             for (String pick : picks) {
757                 if (pick.equalsIgnoreCase(value)) {
758                     return true;
759                 }
760             }
761 
762             return false;
763         }
764         return value != null;
765     }
766 
767     /**
768      * Modify the value if necessary.
769      * 
770      * @param value
771      *            the input
772      * @return either value or a modified version of it.
773      */
774     public String filter(String value) {
775         // Look through the choice array, if present, for matches.
776         if (hasChoices()) {
777             // Do we have an exact match?
778             for (String pick : picks) {
779                 if (pick.equals(value)) {
780                     return value;
781                 }
782             }
783 
784             // Do we have a case insensitive match?
785             for (String pick : picks) {
786                 if (pick.equalsIgnoreCase(value)) {
787                     return pick;
788                 }
789             }
790         }
791 
792         return value;
793     }
794 
795     /**
796      * RTF is allowed in a few config entries.
797      * 
798      * @return true if RTF is allowed
799      */
800     public boolean allowsRTF() {
801         return false;
802     }
803 
804     /**
805      * While most fields are single line or single value, some allow
806      * continuation. A continuation mark is a backslash at the end of a line. It
807      * is not to be followed by whitespace.
808      * 
809      * @return true if continuation is allowed
810      */
811     public boolean allowsContinuation() {
812         return false;
813     }
814 
815     /**
816      * Some keys can repeat. When this happens each is a single value pick from
817      * a list of choices.
818      * 
819      * @return true if this ConfigEntryType can occur more than once
820      */
821     public boolean mayRepeat() {
822         return false;
823     }
824 
825     /**
826      * Determines the level of detail stored in the histogram.
827      * 
828      * @return true if the ConfigEntry should report histogram for repetitions
829      */
830     public boolean reportDetails() {
831         return true;
832     }
833 
834     /**
835      * Some keys can repeat. When this happens each is a single value pick from
836      * a list of choices.
837      * 
838      * @return true if this ConfigEntryType can occur more than once
839      */
840     protected boolean hasChoices() {
841         return picks != null;
842     }
843 
844     /**
845      * Synthetic keys are those that are not in the Sword Book's conf, but are
846      * needed by the program. Typically, these are derived by the program from
847      * the other entries.
848      * 
849      * @return true if this is synthetic
850      */
851     public boolean isSynthetic() {
852         return false;
853     }
854 
855     /**
856      * Some ConfigEntryTypes have defaults.
857      * 
858      * @return the default, if there is one, null otherwise
859      */
860     public Object getDefault() {
861         return defaultValue;
862     }
863 
864     /**
865      * Convert the string value from the conf into the representation of this
866      * ConfigEntryType.
867      * 
868      * @return the converted object
869      */
870     public Object convert(String input) {
871         return input;
872     }
873 
874     /**
875      * Return the original representation of the object.
876      * 
877      * @return the converted object
878      */
879     public String unconvert(Object internal) {
880         if (internal == null) {
881             return null;
882         }
883         return internal.toString();
884     }
885 
886     /**
887      * Lookup method to convert from a String
888      */
889     public static ConfigEntryType fromString(String name) {
890         if (name != null) {
891             // special case
892             if (name.startsWith(ConfigEntryType.HISTORY.toString())) {
893                 return ConfigEntryType.HISTORY;
894             }
895 
896             for (ConfigEntryType o : ConfigEntryType.values()) {
897                 if (name.equals(o.name)) {
898                     return o;
899                 }
900             }
901         }
902 
903         // should not get here.
904         // But there are typos in the keys in the book conf files
905         // And this allows for the addition of new fields in
906         // advance of changing JSword
907         return null;
908     }
909 
910     @Override
911     public String toString() {
912         return name;
913     }
914 
915     /**
916      * The name of the ConfigEntryType
917      */
918     private final String name;
919 
920     /**
921      * The default for the ConfigEntryType
922      */
923     private final Object defaultValue;
924 
925     /**
926      * The array of choices.
927      */
928     private final String[] picks;
929 
930     /**
931      * Constants for direction
932      */
933     public static final String DIRECTION_LTOR = "LtoR";
934     public static final String DIRECTION_RTOL = "RtoL";
935     public static final String DIRECTION_BIDI = "bidi";
936 
937 }
938