1
21 package org.crosswire.jsword.book.sword;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.regex.Pattern;
26
27 import org.crosswire.common.util.Histogram;
28 import org.crosswire.common.util.StringUtil;
29 import org.crosswire.common.xml.XMLUtil;
30 import org.crosswire.jsword.book.OSISUtil;
31 import org.jdom2.Element;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
43 public final class ConfigEntry {
44
45
54 public ConfigEntry(String bookName, String aName) {
55 internal = bookName;
56 name = aName;
57 type = ConfigEntryType.fromString(aName);
58 }
59
60
70 public ConfigEntry(String bookName, ConfigEntryType aType, String aValue) {
71 internal = bookName;
72 name = aType.getName();
73 type = aType;
74 addValue(aValue);
75 }
76
77
80 public String getName() {
81 if (type != null) {
82 return type.getName();
83 }
84 return name;
85 }
86
87
90 public ConfigEntryType getType() {
91 return type;
92 }
93
94
101 public boolean isAllowed(String aValue) {
102 if (type != null) {
103 return type.isAllowed(aValue);
104 }
105 return true;
106 }
107
108
113 public boolean allowsRTF() {
114 if (type != null) {
115 return type.allowsRTF();
116 }
117 return true;
118 }
119
120
127 public boolean allowsContinuation() {
128 if (type != null) {
129 return type.allowsContinuation();
130 }
131 return true;
132 }
133
134
140 public boolean mayRepeat() {
141 if (type != null) {
142 return type.mayRepeat();
143 }
144 return true;
145 }
146
147
150 public boolean reportDetails() {
151 if (type != null) {
152 return type.reportDetails();
153 }
154 return true;
155 }
156
157
162 public boolean isSupported() {
163 return type != null;
164 }
165
166
172 public Object getValue() {
173 if (value != null) {
174 return value;
175 }
176 if (values != null) {
177 return values;
178 }
179 return type.getDefault();
180 }
181
182
189 public boolean match(Object search) {
190 if (value != null) {
191 return value.equals(search);
192 }
193 if (values != null) {
194 return values.contains(search);
195 }
196 Object def = type.getDefault();
197 return def != null && def.equals(search);
198 }
199
200
203 public void addValue(String val) {
204 String aValue = val;
205 String confEntryName = getName();
206 if (type != null) {
208 aValue = type.filter(aValue);
209 }
210
211 if (!allowsRTF() && RTF_PATTERN.matcher(aValue).find()) {
213 log.info("Ignoring unexpected RTF for {} in {}: {}", confEntryName, internal, aValue);
214 }
215
216 if (mayRepeat()) {
217 if (values == null) {
218 histogram.increment(confEntryName);
219 values = new ArrayList<String>();
220 }
221 if (reportDetails()) {
222 histogram.increment(confEntryName + '.' + aValue);
223 }
224 if (!isAllowed(aValue)) {
225 log.info("Ignoring unknown config value for {} in {}: {}", confEntryName, internal, aValue);
226 return;
227 }
228 values.add(aValue);
229 } else {
230 if (value != null) {
231 log.info("Ignoring unexpected additional entry for {} in {}: {}", confEntryName, internal, aValue);
232 } else {
233 histogram.increment(confEntryName);
234 if (type.hasChoices()) {
235 histogram.increment(confEntryName + '.' + aValue);
236 }
237 if (!isAllowed(aValue)) {
238 log.info("Ignoring unknown config value for {} in {}: {}", confEntryName, internal, aValue);
239 return;
240 }
241 value = type.convert(aValue);
242 }
243 }
244 }
245
246 public Element toOSIS() {
247 OSISUtil.OSISFactory factory = OSISUtil.factory();
248
249 Element rowEle = factory.createRow();
250
251 Element nameEle = factory.createCell();
252 Element hiEle = factory.createHI();
253 hiEle.setAttribute(OSISUtil.OSIS_ATTR_TYPE, OSISUtil.HI_BOLD);
254 nameEle.addContent(hiEle);
255 Element valueElement = factory.createCell();
256 rowEle.addContent(nameEle);
257 rowEle.addContent(valueElement);
258
259 hiEle.addContent(getName());
261
262 if (value != null) {
263 String text = value.toString();
264 text = XMLUtil.escape(text);
265 if (allowsRTF()) {
266 valueElement.addContent(OSISUtil.rtfToOsis(text));
267 } else if (allowsContinuation()) {
268 valueElement.addContent(processLines(factory, text));
269 } else {
270 valueElement.addContent(text);
271 }
272 }
273
274 if (values != null) {
275 Element listEle = factory.createLG();
276 valueElement.addContent(listEle);
277
278 for (String str : values) {
279 String text = XMLUtil.escape(str);
280 Element itemEle = factory.createL();
281 listEle.addContent(itemEle);
282 if (allowsRTF()) {
283 itemEle.addContent(OSISUtil.rtfToOsis(text));
284 } else {
285 itemEle.addContent(text);
286 }
287 }
288 }
289 return rowEle;
290 }
291
292 public static void resetStatistics() {
293 histogram.clear();
294 }
295
296 public static void dumpStatistics() {
297 }
300
301 @Override
302 public boolean equals(Object obj) {
303 if (obj == null) {
305 return false;
306 }
307
308 if (!obj.getClass().equals(this.getClass())) {
311 return false;
312 }
313
314 ConfigEntry that = (ConfigEntry) obj;
315 return that.getName().equals(this.getName());
316 }
317
318 @Override
319 public int hashCode() {
320 return getName().hashCode();
321 }
322
323 @Override
324 public String toString() {
325 return getName();
326 }
327
328
335 public String toConf() {
336 StringBuilder buf = new StringBuilder();
337
338 if (value != null) {
339 buf.append(getName());
340 buf.append('=');
341 String text = getConfValue(value);
342 if (allowsContinuation()) {
343 text = text.replaceAll("\n", "\\\\\n");
346 }
347 buf.append(text);
348 buf.append('\n');
349 } else if (type.equals(ConfigEntryType.CIPHER_KEY)) {
350 buf.append(getName());
352 buf.append('=');
353 }
354
355 if (values != null) {
356 if (type.equals(ConfigEntryType.HISTORY)) {
360 for (String text : values) {
361 buf.append(getName());
362 buf.append('_');
363 buf.append(text.replaceFirst(" ", "="));
364 buf.append('\n');
365 }
366 } else {
367 for (String text : values) {
368 buf.append(getName());
369 buf.append('=');
370 buf.append(getConfValue(text));
371 buf.append('\n');
372 }
373 }
374 }
375 return buf.toString();
376 }
377
378
385 private String getConfValue(Object aValue) {
386 if (aValue != null) {
387 if (type != null) {
388 return type.unconvert(aValue);
389 }
390 return aValue.toString();
391 }
392 return null;
393 }
394
395 private List<Element> processLines(OSISUtil.OSISFactory factory, String aValue) {
396 List<Element> list = new ArrayList<Element>();
397 String[] lines = StringUtil.splitAll(aValue, '\n');
398 for (int i = 0; i < lines.length; i++) {
399 Element lineElement = factory.createL();
400 lineElement.addContent(lines[i]);
401 list.add(lineElement);
402 }
403 return list;
404 }
405
406
410 private static final Pattern RTF_PATTERN = Pattern.compile("\\\\pard|\\\\pa[er]|\\\\qc|\\\\[bi]|\\\\u-?[0-9]{4,6}+");
411
412
415 private static Histogram histogram = new Histogram();
416
417 private ConfigEntryType type;
418 private String internal;
419 private String name;
420 private List<String> values;
421 private Object value;
422
423
426 private static final Logger log = LoggerFactory.getLogger(ConfigEntry.class);
427 }
428