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: 2008
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12:48:02Z dmsmith $
21   */
22  
23  package org.crosswire.common.options;
24  
25  import java.util.ArrayList;
26  import java.util.LinkedHashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  /**
31   * An OptionList contains an ordered set of Options. The primary ability of an
32   * OptionList is to find the matches for an Option.
33   * 
34   * @see gnu.lgpl.License for license details.<br>
35   *      The copyright to this program is held by it's authors.
36   * @author DM Smith [dmsmith555 at yahoo dot com]
37   */
38  public class OptionList {
39      public OptionList() {
40          longOptions = new LinkedHashMap<String, Option>();
41          shortOptions = new LinkedHashMap<String, Option>();
42      }
43  
44      /**
45       * Adds an Option to the end of this OptionList. It is an error with
46       * "undefined" behavior for an Option's short or long name to already be
47       * known.
48       * 
49       * @param option
50       */
51      public void add(Option option) {
52          char shortName = option.getShortName();
53          String longName = option.getLongName();
54          if (shortName != '\u0000') {
55              String optionName = Character.toString(shortName);
56              assert !shortOptions.containsKey(optionName) : optionName + " already present";
57              shortOptions.put(optionName, option);
58          }
59  
60          if (longName != null) {
61              assert !longOptions.containsKey(longName) : longName + " already present";
62              longOptions.put(longName, option);
63          }
64      }
65  
66      /**
67       * Get a list of Options that match the Option's long name. Return all
68       * Options where the key is a prefix of its long name. If there is an exact
69       * match then it is at the head of the list. It is up to the program to
70       * decide how to handle ambiguity.
71       * 
72       * @param key
73       *            the input to match
74       * @return a list of all matches, or an empty list
75       */
76      public List<Option> getLongOptions(String key) {
77          List<Option> matches = new ArrayList<Option>();
78          if (longOptions.containsKey(key)) {
79              matches.add(longOptions.get(key));
80          }
81  
82          for (Map.Entry<String, Option> entry : longOptions.entrySet()) {
83              String entryKey = entry.getKey();
84              Option entryValue = entry.getValue();
85              if (entryKey.startsWith(key) && !matches.contains(entryValue)) {
86                  matches.add(entryValue);
87              }
88          }
89  
90          return matches;
91      }
92  
93      /**
94       * Get the Option that matches the key on the Option's short name.
95       * 
96       * @param key
97       *            the input to match
98       * @return the matching Option, null otherwise.
99       */
100     public Option getShortOption(char key) {
101         String optionName = Character.toString(key);
102 
103         Option match = null;
104         if (shortOptions.containsKey(optionName)) {
105             match = shortOptions.get(optionName);
106         }
107 
108         return match;
109     }
110 
111     /**
112      * Get a list of Options that match the Option's short or long name.
113      * Obviously, if the key is longer than a single character it won't match a
114      * short name. Return all Options where the key is a prefix of its long
115      * name. If there is an exact match then it is at the head of the list. It
116      * is up to the program to decide how to handle ambiguity.
117      * 
118      * @param key
119      *            the input to match
120      * @return a list of all matches, or an empty list
121      */
122     public List<Option> getOptions(String key) {
123         List<Option> matches = new ArrayList<Option>();
124         if (key.length() == 1) {
125             Option match = getShortOption(key.charAt(0));
126             if (match != null) {
127                 matches.add(match);
128             }
129         }
130 
131         for (Option match : getLongOptions(key)) {
132             if (!matches.contains(match)) {
133                 matches.add(match);
134             }
135         }
136 
137         return matches;
138     }
139 
140     private Map<String, Option> shortOptions;
141     private Map<String, Option> longOptions;
142 }
143