Merge branch 'edit-wot-trust' into next
[Sone.git] / src / main / java / net / pterodactylus / sone / core / Options.java
1 package net.pterodactylus.sone.core;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 /**
11  * Stores various options that influence Sone’s behaviour.
12  *
13  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
14  */
15 public class Options {
16
17         /**
18          * Contains current and default value of an option.
19          *
20          * @param <T>
21          *            The type of the option
22          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
23          */
24         public static interface Option<T> {
25
26                 /**
27                  * Returns the default value of the option.
28                  *
29                  * @return The default value of the option
30                  */
31                 public T getDefault();
32
33                 /**
34                  * Returns the current value of the option. If the current value is not
35                  * set (usually {@code null}), the default value is returned.
36                  *
37                  * @return The current value of the option
38                  */
39                 public T get();
40
41                 /**
42                  * Returns the real value of the option. This will also return an unset
43                  * value (usually {@code null})!
44                  *
45                  * @return The real value of the option
46                  */
47                 public T getReal();
48
49                 /**
50                  * Sets the current value of the option.
51                  *
52                  * @param value
53                  *            The new value of the option
54                  */
55                 public void set(T value);
56
57         }
58
59         /**
60          * Interface for objects that want to be notified when an option changes its
61          * value.
62          *
63          * @param <T>
64          *            The type of the option
65          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
66          */
67         public static interface OptionWatcher<T> {
68
69                 /**
70                  * Notifies an object that an option has been changed.
71                  *
72                  * @param option
73                  *            The option that has changed
74                  * @param oldValue
75                  *            The old value of the option
76                  * @param newValue
77                  *            The new value of the option
78                  */
79                 public void optionChanged(Option<T> option, T oldValue, T newValue);
80
81         }
82
83         /**
84          * Basic implementation of an {@link Option} that notifies an
85          * {@link OptionWatcher} if the value changes.
86          *
87          * @param <T>
88          *            The type of the option
89          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
90          */
91         public static class DefaultOption<T> implements Option<T> {
92
93                 /** The default value. */
94                 private final T defaultValue;
95
96                 /** The current value. */
97                 private volatile T value;
98
99                 /** The option watcher. */
100                 private final List<OptionWatcher<T>> optionWatchers = new ArrayList<OptionWatcher<T>>();
101
102                 /**
103                  * Creates a new default option.
104                  *
105                  * @param defaultValue
106                  *            The default value of the option
107                  * @param optionWatchers
108                  *            The option watchers
109                  */
110                 public DefaultOption(T defaultValue, OptionWatcher<T>... optionWatchers) {
111                         this.defaultValue = defaultValue;
112                         this.optionWatchers.addAll(Arrays.asList(optionWatchers));
113                 }
114
115                 /**
116                  * {@inheritDoc}
117                  */
118                 @Override
119                 public T getDefault() {
120                         return defaultValue;
121                 }
122
123                 /**
124                  * {@inheritDoc}
125                  */
126                 @Override
127                 public T get() {
128                         return (value != null) ? value : defaultValue;
129                 }
130
131                 /**
132                  * Returns the real value of the option. This will also return an unset
133                  * value (usually {@code null})!
134                  *
135                  * @return The real value of the option
136                  */
137                 @Override
138                 public T getReal() {
139                         return value;
140                 }
141
142                 /**
143                  * {@inheritDoc}
144                  */
145                 @Override
146                 public void set(T value) {
147                         T oldValue = this.value;
148                         this.value = value;
149                         if (!get().equals(oldValue)) {
150                                 for (OptionWatcher<T> optionWatcher : optionWatchers) {
151                                         optionWatcher.optionChanged(this, oldValue, get());
152                                 }
153                         }
154                 }
155
156         }
157
158         /** Holds all {@link Boolean} {@link Option}s. */
159         private final Map<String, Option<Boolean>> booleanOptions = Collections.synchronizedMap(new HashMap<String, Option<Boolean>>());
160
161         /** Holds all {@link Integer} {@link Option}s. */
162         private final Map<String, Option<Integer>> integerOptions = Collections.synchronizedMap(new HashMap<String, Option<Integer>>());
163
164         /** Holds all {@link String} {@link Option}s. */
165         private final Map<String, Option<String>> stringOptions = Collections.synchronizedMap(new HashMap<String, Option<String>>());
166
167         /**
168          * Adds a boolean option.
169          *
170          * @param name
171          *            The name of the option
172          * @param booleanOption
173          *            The option
174          * @return The given option
175          */
176         public Option<Boolean> addBooleanOption(String name, Option<Boolean> booleanOption) {
177                 booleanOptions.put(name, booleanOption);
178                 return booleanOption;
179         }
180
181         /**
182          * Returns the boolean option with the given name.
183          *
184          * @param name
185          *            The name of the option
186          * @return The option, or {@code null} if there is no option with the given
187          *         name
188          */
189         public Option<Boolean> getBooleanOption(String name) {
190                 return booleanOptions.get(name);
191         }
192
193         /**
194          * Adds an {@link Integer} {@link Option}.
195          *
196          * @param name
197          *            The name of the option
198          * @param integerOption
199          *            The option
200          * @return The given option
201          */
202         public Option<Integer> addIntegerOption(String name, Option<Integer> integerOption) {
203                 integerOptions.put(name, integerOption);
204                 return integerOption;
205         }
206
207         /**
208          * Returns an {@link Integer} {@link Option}.
209          *
210          * @param name
211          *            The name of the integer option to get
212          * @return The integer option, or {@code null} if there is no option with
213          *         the given name
214          */
215         public Option<Integer> getIntegerOption(String name) {
216                 return integerOptions.get(name);
217         }
218
219         /**
220          * Adds a {@link String} {@link Option}.
221          *
222          * @param name
223          *            The name of the option
224          * @param stringOption
225          *            The option
226          * @return The given option
227          */
228         public Option<String> addStringOption(String name, Option<String> stringOption) {
229                 stringOptions.put(name, stringOption);
230                 return stringOption;
231         }
232
233         /**
234          * Returns a {@link String} {@link Option}.
235          *
236          * @param name
237          *            The name of the string option to get
238          * @return The string option, or {@code null} if there is no option with the
239          *         given name
240          */
241         public Option<String> getStringOption(String name) {
242                 return stringOptions.get(name);
243         }
244
245 }