Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQSelect.java @ 3818:dc18457b1cef
merged flys-artifacts/pre2.7-2012-03-16
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:59 +0200 |
parents | efb2038783f9 |
children | 71086a3a1c5f |
comparison
equal
deleted
inserted
replaced
2456:60ab1054069d | 3818:dc18457b1cef |
---|---|
1 package de.intevation.flys.artifacts.states; | |
2 | |
3 import java.text.NumberFormat; | |
4 | |
5 import gnu.trove.TDoubleArrayList; | |
6 | |
7 import org.apache.log4j.Logger; | |
8 | |
9 import org.w3c.dom.Element; | |
10 | |
11 import de.intevation.artifacts.Artifact; | |
12 import de.intevation.artifacts.CallContext; | |
13 | |
14 import de.intevation.artifacts.common.utils.XMLUtils; | |
15 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; | |
16 | |
17 import de.intevation.artifactdatabase.ProtocolUtils; | |
18 import de.intevation.artifactdatabase.data.StateData; | |
19 | |
20 import de.intevation.flys.model.Gauge; | |
21 import de.intevation.flys.model.River; | |
22 import de.intevation.flys.model.Wst; | |
23 | |
24 import de.intevation.flys.artifacts.FLYSArtifact; | |
25 import de.intevation.flys.artifacts.WINFOArtifact; | |
26 | |
27 import de.intevation.flys.artifacts.model.WstFactory; | |
28 import de.intevation.flys.artifacts.resources.Resources; | |
29 | |
30 import de.intevation.flys.utils.FLYSUtils; | |
31 | |
32 | |
33 /** | |
34 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
35 */ | |
36 public class WQSelect extends DefaultState { | |
37 | |
38 /** The logger used in this class. */ | |
39 private static Logger logger = Logger.getLogger(WQSelect.class); | |
40 | |
41 /** The default step width for Qs. */ | |
42 public static final String DEFAULT_STEP_Q = "50"; | |
43 | |
44 /** The default step width for Qs. */ | |
45 public static final String DEFAULT_STEP_W = "30"; | |
46 | |
47 /** The max number of steps for Qs and Ws. */ | |
48 public static final int MAX_STEPS = 30; | |
49 | |
50 /** The name of the 'mode' field. */ | |
51 public static final String WQ_MODE = "wq_isq"; | |
52 | |
53 /** Them name fo the 'free' field. */ | |
54 public static final String WQ_FREE = "wq_isfree"; | |
55 | |
56 /** The name of the 'selection' field. */ | |
57 public static final String WQ_SELECTION = "wq_isrange"; | |
58 | |
59 /** The name of the 'from' field. */ | |
60 public static final String WQ_FROM = "wq_from"; | |
61 | |
62 /** The name of the 'to' field. */ | |
63 public static final String WQ_TO = "wq_to"; | |
64 | |
65 /** The name of the 'step' field. */ | |
66 public static final String WQ_STEP = "wq_step"; | |
67 | |
68 /** The name of the 'single' field. */ | |
69 public static final String WQ_SINGLE = "wq_single"; | |
70 | |
71 | |
72 /** | |
73 * The default constructor that initializes an empty State object. | |
74 */ | |
75 public WQSelect() { | |
76 } | |
77 | |
78 | |
79 @Override | |
80 protected Element createStaticData( | |
81 FLYSArtifact flys, | |
82 ElementCreator creator, | |
83 CallContext cc, | |
84 String name, | |
85 String value, | |
86 String type | |
87 ) { | |
88 if (!name.equals(WQ_SINGLE)) { | |
89 return super.createStaticData(flys, creator, cc, name, value, type); | |
90 } | |
91 | |
92 Boolean isQ = flys.getDataAsBoolean(WQ_MODE); | |
93 Boolean isFree = flys.getDataAsBoolean(WQ_FREE); | |
94 | |
95 WINFOArtifact winfo = (WINFOArtifact) flys; | |
96 | |
97 Element dataElement = creator.create("data"); | |
98 creator.addAttr(dataElement, "name", name, true); | |
99 creator.addAttr(dataElement, "type", type, true); | |
100 | |
101 Element itemElement = creator.create("item"); | |
102 creator.addAttr(itemElement, "value", value, true); | |
103 | |
104 String label; | |
105 | |
106 if (!isQ || isFree) { | |
107 label = getLabel(winfo, cc, value); | |
108 } | |
109 else { | |
110 label = getSpecialLabel(winfo, cc, value); | |
111 } | |
112 | |
113 creator.addAttr(itemElement, "label", label, true); | |
114 | |
115 dataElement.appendChild(itemElement); | |
116 | |
117 return dataElement; | |
118 } | |
119 | |
120 | |
121 protected static String getLabel( | |
122 WINFOArtifact winfo, | |
123 CallContext cc, | |
124 String raw | |
125 ) { | |
126 String[] values = raw.split(" "); | |
127 | |
128 if (values.length < 1) { | |
129 return null; | |
130 } | |
131 | |
132 StringBuilder label = new StringBuilder(); | |
133 | |
134 NumberFormat nf = NumberFormat.getInstance( | |
135 Resources.getLocale(cc.getMeta())); | |
136 | |
137 for (String value: values) { | |
138 try { | |
139 double v = Double.parseDouble(value.trim()); | |
140 | |
141 String formatted = nf.format(v); | |
142 | |
143 if (label.length() > 0) { | |
144 label.append(';'); | |
145 } | |
146 label.append(formatted); | |
147 } | |
148 catch (NumberFormatException nfe) { | |
149 // do nothing here | |
150 } | |
151 } | |
152 | |
153 return label.toString(); | |
154 } | |
155 | |
156 | |
157 protected static String getSpecialLabel( | |
158 WINFOArtifact winfo, | |
159 CallContext cc, | |
160 String raw | |
161 ) { | |
162 String[] values = raw.split(" "); | |
163 | |
164 if (values.length < 1) { | |
165 return null; | |
166 } | |
167 | |
168 NumberFormat nf = NumberFormat.getInstance( | |
169 Resources.getLocale(cc.getMeta())); | |
170 | |
171 Gauge gauge = winfo.getGauge(); | |
172 | |
173 boolean debug = logger.isDebugEnabled(); | |
174 | |
175 StringBuilder label = new StringBuilder(); | |
176 | |
177 for (String value: values) { | |
178 try { | |
179 double v = Double.parseDouble(value.trim()); | |
180 | |
181 String tmp = nf.format(v); | |
182 String mv = FLYSUtils.getNamedMainValue(gauge, v); | |
183 | |
184 if (mv != null && mv.length() > 0) { | |
185 tmp = mv + ": " + tmp; | |
186 if (debug) { | |
187 logger.debug("Add main value: '" + mv + "'"); | |
188 } | |
189 } | |
190 if (label.length() > 0) { | |
191 label.append(';'); | |
192 } | |
193 label.append(tmp); | |
194 } | |
195 catch (NumberFormatException nfe) { | |
196 // do nothing here | |
197 } | |
198 } | |
199 | |
200 return label.toString(); | |
201 } | |
202 | |
203 | |
204 @Override | |
205 protected Element createData( | |
206 XMLUtils.ElementCreator cr, | |
207 Artifact artifact, | |
208 StateData data, | |
209 CallContext context) | |
210 { | |
211 Element select = ProtocolUtils.createArtNode( | |
212 cr, "select", null, null); | |
213 | |
214 cr.addAttr(select, "name", data.getName(), true); | |
215 | |
216 Element label = ProtocolUtils.createArtNode( | |
217 cr, "label", null, null); | |
218 | |
219 Element choices = ProtocolUtils.createArtNode( | |
220 cr, "choices", null, null); | |
221 | |
222 label.setTextContent(Resources.getMsg( | |
223 context.getMeta(), | |
224 data.getName(), | |
225 data.getName())); | |
226 | |
227 select.appendChild(label); | |
228 | |
229 return select; | |
230 } | |
231 | |
232 | |
233 @Override | |
234 protected Element[] createItems( | |
235 XMLUtils.ElementCreator cr, | |
236 Artifact artifact, | |
237 String name, | |
238 CallContext context) | |
239 { | |
240 double[] minmaxW = determineMinMaxW(artifact); | |
241 double[] minmaxQ = determineMinMaxQAtGauge(artifact); | |
242 double[] minmaxQFree = determineMinMaxQ(artifact); | |
243 | |
244 if (name.equals("wq_from")) { | |
245 Element minW = createItem(cr, new String[] { | |
246 "minW", | |
247 String.valueOf(minmaxW[0])}); | |
248 | |
249 Element minQ = createItem(cr, new String[] { | |
250 "minQ", | |
251 String.valueOf(minmaxQ[0])}); | |
252 | |
253 Element minQFree = createItem(cr, new String[] { | |
254 "minQFree", | |
255 String.valueOf(minmaxQFree[0])}); | |
256 | |
257 return new Element[] { minW, minQ, minQFree }; | |
258 } | |
259 else if (name.equals("wq_to")) { | |
260 Element maxW = createItem(cr, new String[] { | |
261 "maxW", | |
262 String.valueOf(minmaxW[1])}); | |
263 | |
264 Element maxQ = createItem(cr, new String[] { | |
265 "maxQ", | |
266 String.valueOf(minmaxQ[1])}); | |
267 | |
268 Element maxQFree = createItem(cr, new String[] { | |
269 "maxQFree", | |
270 String.valueOf(minmaxQFree[1])}); | |
271 | |
272 return new Element[] { maxW, maxQ, maxQFree }; | |
273 } | |
274 else { | |
275 Element stepW = createItem( | |
276 cr, new String[] { | |
277 "stepW", | |
278 String.valueOf(getStepsW(minmaxW[0], minmaxW[1]))}); | |
279 Element stepQ = createItem( | |
280 cr, new String[] { | |
281 "stepQ", | |
282 String.valueOf(getStepsQ(minmaxQ[0], minmaxQ[1]))}); | |
283 Element stepQFree = createItem( | |
284 cr, new String[] { | |
285 "stepQFree", | |
286 String.valueOf(getStepsQ(minmaxQFree[0], minmaxQFree[1]))}); | |
287 | |
288 return new Element[] { stepW, stepQ, stepQFree }; | |
289 } | |
290 } | |
291 | |
292 | |
293 protected static double getStepsW(double min, double max) { | |
294 double diff = min < max ? max - min : min - max; | |
295 double step = diff / MAX_STEPS; | |
296 | |
297 if (step < 10) { | |
298 return getSteps(step, 1); | |
299 } | |
300 else if (step < 100) { | |
301 return getSteps(step, 10); | |
302 } | |
303 else if (step < 1000) { | |
304 return getSteps(step, 100); | |
305 } | |
306 else { | |
307 return step; | |
308 } | |
309 } | |
310 | |
311 | |
312 protected static double getStepsQ(double min, double max) { | |
313 double diff = min < max ? max - min : min - max; | |
314 double step = diff / MAX_STEPS; | |
315 | |
316 if (step < 10) { | |
317 return getSteps(step, 1); | |
318 } | |
319 else if (step < 100) { | |
320 return getSteps(step, 10); | |
321 } | |
322 else if (step < 1000) { | |
323 return getSteps(step, 100); | |
324 } | |
325 else { | |
326 return step; | |
327 } | |
328 } | |
329 | |
330 | |
331 protected static double getSteps(double steps, double factor) { | |
332 int fac = (int) steps / 10; | |
333 double diff = steps - fac * 10; | |
334 | |
335 if (diff == 0) { | |
336 return steps; | |
337 } | |
338 | |
339 return 10d * (fac + 1); | |
340 } | |
341 | |
342 | |
343 protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { | |
344 Element item = ProtocolUtils.createArtNode(cr, "item", null, null); | |
345 Element label = ProtocolUtils.createArtNode(cr, "label", null, null); | |
346 Element value = ProtocolUtils.createArtNode(cr, "value", null, null); | |
347 | |
348 String[] arr = (String[]) obj; | |
349 | |
350 label.setTextContent(arr[0]); | |
351 value.setTextContent(arr[1]); | |
352 | |
353 item.appendChild(label); | |
354 item.appendChild(value); | |
355 | |
356 return item; | |
357 } | |
358 | |
359 | |
360 @Override | |
361 protected String getUIProvider() { | |
362 return "wq_panel"; | |
363 } | |
364 | |
365 | |
366 /** | |
367 * Determines the min and max W value for the current gauge. If no min and | |
368 * max values could be determined, this method will return | |
369 * [Double.MIN_VALUE, Double.MAX_VALUE]. | |
370 * | |
371 * @param artifact The FLYSArtifact. | |
372 * | |
373 * @return the min and max W values for the current gauge. | |
374 */ | |
375 protected double[] determineMinMaxW(Artifact artifact) { | |
376 logger.debug("WQSelect.determineCurrentGauge"); | |
377 | |
378 Gauge gauge = ((WINFOArtifact) artifact).getGauge(); | |
379 double[] minmaxW = gauge != null ? gauge.determineMinMaxW() : null; | |
380 | |
381 double minW = minmaxW != null ? minmaxW[0] : Double.MIN_VALUE; | |
382 double maxW = minmaxW != null ? minmaxW[1] : Double.MAX_VALUE; | |
383 | |
384 return new double[] { minW, maxW }; | |
385 } | |
386 | |
387 | |
388 /** | |
389 * Determines the min and max Q value for the current gauge. If no min and | |
390 * max values could be determined, this method will return | |
391 * [Double.MIN_VALUE, Double.MAX_VALUE]. | |
392 * | |
393 * @param artifact The FLYSArtifact. | |
394 * | |
395 * @return the min and max Q values for the current gauge. | |
396 */ | |
397 protected double[] determineMinMaxQAtGauge(Artifact artifact) { | |
398 logger.debug("WQSelect.determineMinMaxQAtGauge"); | |
399 | |
400 WINFOArtifact flysArtifact = (WINFOArtifact) artifact; | |
401 | |
402 River river = FLYSUtils.getRiver(flysArtifact); | |
403 Gauge gauge = flysArtifact.getGauge(); | |
404 Wst wst = WstFactory.getWst(river); | |
405 | |
406 double[] minmaxQ = gauge != null | |
407 ? wst.determineMinMaxQ(gauge.getRange()) | |
408 : null; | |
409 | |
410 double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE; | |
411 double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE; | |
412 | |
413 return new double[] { minQ, maxQ }; | |
414 } | |
415 | |
416 | |
417 /** | |
418 * Determines the min and max Q value for the current kilometer range. If no | |
419 * min and max values could be determined, this method will return | |
420 * | |
421 * @param artifact The FLYSArtifact. | |
422 * | |
423 * @return the min and max Q values for the current kilometer range. | |
424 */ | |
425 protected double[] determineMinMaxQ(Artifact artifact) { | |
426 logger.debug("WQSelect.determineMinMaxQ"); | |
427 | |
428 FLYSArtifact flys = (FLYSArtifact) artifact; | |
429 double[] kms = FLYSUtils.getKmRange(flys); | |
430 | |
431 if (kms == null || kms.length == 0) { | |
432 return new double[] { Double.MIN_VALUE, Double.MAX_VALUE }; | |
433 } | |
434 | |
435 River river = FLYSUtils.getRiver(flys); | |
436 Wst wst = WstFactory.getWst(river); | |
437 | |
438 logger.debug("User defined KMs: " + kms[0] + " - " + kms[kms.length-1]); | |
439 | |
440 double[] minmaxQ = wst.determineMinMaxQFree(kms[0]); | |
441 | |
442 return minmaxQ != null | |
443 ? minmaxQ | |
444 : new double[] { Double.MIN_VALUE, Double.MAX_VALUE }; | |
445 } | |
446 | |
447 | |
448 @Override | |
449 public boolean validate(Artifact artifact) | |
450 throws IllegalArgumentException | |
451 { | |
452 logger.debug("WQSelect.validate"); | |
453 | |
454 WINFOArtifact flys = (WINFOArtifact) artifact; | |
455 | |
456 StateData data = getData(flys, WQ_SELECTION); | |
457 boolean isRange = data != null | |
458 ? Boolean.valueOf((String) data.getValue()) | |
459 : false; | |
460 | |
461 | |
462 | |
463 if (!isRange) { | |
464 return validateSingle(artifact); | |
465 } | |
466 else { | |
467 return validateRange(artifact); | |
468 } | |
469 } | |
470 | |
471 | |
472 protected boolean validateBounds( | |
473 double fromValid, double toValid, | |
474 double from, double to, double step) | |
475 throws IllegalArgumentException | |
476 { | |
477 logger.debug("RangeState.validateRange"); | |
478 | |
479 if (from < fromValid) { | |
480 logger.error( | |
481 "Invalid 'from'. " + from + " is smaller than " + fromValid); | |
482 throw new IllegalArgumentException("error_feed_from_out_of_range"); | |
483 } | |
484 else if (to > toValid) { | |
485 logger.error( | |
486 "Invalid 'to'. " + to + " is bigger than " + toValid); | |
487 throw new IllegalArgumentException("error_feed_to_out_of_range"); | |
488 } | |
489 | |
490 return true; | |
491 } | |
492 | |
493 | |
494 protected boolean validateSingle(Artifact artifact) | |
495 throws IllegalArgumentException | |
496 { | |
497 logger.debug("WQSelect.validateSingle"); | |
498 | |
499 WINFOArtifact flys = (WINFOArtifact) artifact; | |
500 StateData data = getData(flys, WQ_SINGLE); | |
501 | |
502 String tmp = data != null ? (String) data.getValue() : null; | |
503 | |
504 if (tmp == null || tmp.length() == 0) { | |
505 throw new IllegalArgumentException("error_empty_state"); | |
506 } | |
507 | |
508 String[] strValues = tmp.split(" "); | |
509 TDoubleArrayList all = new TDoubleArrayList(); | |
510 | |
511 for (String strValue: strValues) { | |
512 try { | |
513 all.add(Double.parseDouble(strValue)); | |
514 } | |
515 catch (NumberFormatException nfe) { | |
516 logger.warn(nfe, nfe); | |
517 } | |
518 } | |
519 | |
520 all.sort(); | |
521 | |
522 FLYSUtils.WQ_MODE mode = FLYSUtils.getWQMode(flys); | |
523 | |
524 logger.debug("WQ Mode: " + mode); | |
525 | |
526 double[] minmax = null; | |
527 | |
528 if (mode == FLYSUtils.WQ_MODE.WGAUGE) { | |
529 minmax = determineMinMaxW(artifact); | |
530 } | |
531 else if (mode == FLYSUtils.WQ_MODE.QGAUGE) { | |
532 minmax = determineMinMaxQAtGauge(artifact); | |
533 } | |
534 else { | |
535 minmax = determineMinMaxQ(artifact); | |
536 } | |
537 | |
538 double min = all.get(0); | |
539 double max = all.get(all.size()-1); | |
540 | |
541 logger.debug("Inserted min value = " + min); | |
542 logger.debug("Inserted max value = " + max); | |
543 | |
544 return validateBounds(minmax[0], minmax[1], min, max, 0d); | |
545 } | |
546 | |
547 | |
548 protected boolean validateRange(Artifact artifact) | |
549 throws IllegalArgumentException | |
550 { | |
551 logger.debug("WQSelect.validateRange"); | |
552 | |
553 WINFOArtifact flys = (WINFOArtifact) artifact; | |
554 FLYSUtils.WQ_MODE mode = FLYSUtils.getWQMode(flys); | |
555 | |
556 if (mode == null) { | |
557 throw new IllegalArgumentException("error_feed_invalid_wq_mode"); | |
558 } | |
559 | |
560 StateData dFrom = flys.getData(WQ_FROM); | |
561 StateData dTo = flys.getData(WQ_TO); | |
562 StateData dStep = flys.getData(WQ_STEP); | |
563 | |
564 String fromStr = dFrom != null ? (String) dFrom.getValue() : null; | |
565 String toStr = dTo != null ? (String) dTo.getValue() : null; | |
566 String stepStr = dStep != null ? (String) dStep.getValue() : null; | |
567 | |
568 if (fromStr == null || toStr == null || stepStr == null) { | |
569 throw new IllegalArgumentException("error_empty_state"); | |
570 } | |
571 | |
572 try { | |
573 double from = Double.parseDouble(fromStr); | |
574 double to = Double.parseDouble(toStr); | |
575 double step = Double.parseDouble(stepStr); | |
576 | |
577 if (mode == FLYSUtils.WQ_MODE.WGAUGE) { | |
578 return validateGaugeW(artifact, from, to, step); | |
579 } | |
580 else if (mode == FLYSUtils.WQ_MODE.QGAUGE) { | |
581 return validateGaugeQ(artifact, from, to, step); | |
582 } | |
583 else if (mode == FLYSUtils.WQ_MODE.QFREE) { | |
584 return validateFreeQ(artifact, from, to, step); | |
585 } | |
586 else { | |
587 throw new IllegalArgumentException( | |
588 "error_feed_invalid_wq_mode"); | |
589 } | |
590 } | |
591 catch (NumberFormatException nfe) { | |
592 throw new IllegalArgumentException("error_feed_number_format"); | |
593 } | |
594 } | |
595 | |
596 | |
597 /** | |
598 * Validates the inserted W values. | |
599 * | |
600 * @param artifact The owner artifact. | |
601 * @param from The lower value of the W range. | |
602 * @param to The upper value of the W range. | |
603 * @param step The step width. | |
604 * | |
605 * @return true, if everything was fine, otherwise an exception is thrown. | |
606 */ | |
607 protected boolean validateGaugeW( | |
608 Artifact artifact, | |
609 double from, | |
610 double to, | |
611 double step) | |
612 throws IllegalArgumentException | |
613 { | |
614 logger.debug("WQSelect.validateGaugeW"); | |
615 | |
616 double[] minmaxW = determineMinMaxW(artifact); | |
617 | |
618 return validateBounds(minmaxW[0], minmaxW[1], from, to, step); | |
619 } | |
620 | |
621 | |
622 /** | |
623 * Validates the inserted Q values based on the Q range for the current | |
624 * gauge. | |
625 * | |
626 * @param artifact The owner artifact. | |
627 * @param from The lower value of the Q range. | |
628 * @param to The upper value of the Q range. | |
629 * @param step The step width. | |
630 * | |
631 * @return true, if everything was fine, otherwise an exception is thrown. | |
632 */ | |
633 protected boolean validateGaugeQ( | |
634 Artifact artifact, | |
635 double from, | |
636 double to, | |
637 double step) | |
638 throws IllegalArgumentException | |
639 { | |
640 logger.debug("WQSelect.validateGaugeQ"); | |
641 | |
642 double[] minmaxQ = determineMinMaxQAtGauge(artifact); | |
643 | |
644 return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step); | |
645 } | |
646 | |
647 | |
648 /** | |
649 * Validates the inserted Q values based on the Q range for the current | |
650 * kilometer range. | |
651 * | |
652 * @param artifact The owner artifact. | |
653 * @param from The lower value of the Q range. | |
654 * @param to The upper value of the Q range. | |
655 * @param step The step width. | |
656 * | |
657 * @return true, if everything was fine, otherwise an exception is thrown. | |
658 */ | |
659 protected boolean validateFreeQ( | |
660 Artifact artifact, | |
661 double from, | |
662 double to, | |
663 double step) | |
664 throws IllegalArgumentException | |
665 { | |
666 logger.debug("WQSelect.validateFreeQ"); | |
667 | |
668 double[] minmaxQ = determineMinMaxQ(artifact); | |
669 | |
670 return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step); | |
671 } | |
672 } | |
673 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |