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