comparison artifacts/src/main/java/org/dive4elements/river/artifacts/states/WQAdapted.java @ 5838:5aa05a7a34b7

Rename modules to more fitting names.
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 15:23:37 +0200
parents flys-artifacts/src/main/java/org/dive4elements/river/artifacts/states/WQAdapted.java@bd047b71ab37
children 4897a58c8746
comparison
equal deleted inserted replaced
5837:d9901a08d0a6 5838:5aa05a7a34b7
1 package org.dive4elements.river.artifacts.states;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Comparator;
6 import java.util.Collections;
7
8 import org.apache.log4j.Logger;
9
10 import org.w3c.dom.Element;
11
12 import org.dive4elements.artifacts.Artifact;
13 import org.dive4elements.artifacts.CallContext;
14
15 import org.dive4elements.artifactdatabase.ProtocolUtils;
16 import org.dive4elements.artifactdatabase.data.StateData;
17
18 import org.dive4elements.artifacts.common.utils.XMLUtils;
19
20 import org.dive4elements.river.artifacts.access.RangeAccess;
21
22 import org.dive4elements.river.model.Gauge;
23 import org.dive4elements.river.model.Range;
24 import org.dive4elements.river.model.River;
25 import org.dive4elements.river.model.Wst;
26
27 import org.dive4elements.river.artifacts.FLYSArtifact;
28
29 import org.dive4elements.river.artifacts.model.RangeWithValues;
30 import org.dive4elements.river.artifacts.model.WstFactory;
31 import org.dive4elements.river.utils.FLYSUtils;
32
33
34 /**
35 * State to input W/Q data.
36 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
37 */
38 public class WQAdapted extends DefaultState {
39
40 /** The logger used in this state.*/
41 private static Logger logger = Logger.getLogger(WQAdapted.class);
42
43 public static final String FIELD_WQ_MODE = "wq_isq";
44
45 public static final String FIELD_WQ_VALUES = "wq_values";
46
47 public static final class GaugeOrder implements Comparator<Gauge> {
48 private int order;
49
50 public GaugeOrder(boolean up) {
51 order = up ? 1 : -1;
52 }
53
54 public int compare(Gauge a, Gauge b) {
55 return order * a.getRange().getA().compareTo(b.getRange().getA());
56 }
57 } // class GaugeOrder
58
59 public static final GaugeOrder GAUGE_UP = new GaugeOrder(true);
60 public static final GaugeOrder GAUGE_DOWN = new GaugeOrder(false);
61
62
63 /** Trivial, empty constructor. */
64 public WQAdapted() {
65 }
66
67
68 /**
69 * This method creates one element for each gauge of the selected river that
70 * is intersected by the given kilometer range. Each element is a tuple of
71 * (from;to) where <i>from</i> is the lower bounds of the gauge or the lower
72 * kilometer range. <i>to</i> is the upper bounds of the gauge or the upper
73 * kilometer range.
74 *
75 * @param cr The ElementCreator.
76 * @param artifact The FLYS artifact.
77 * @param name The name of the data item.
78 * @param context The CallContext.
79 *
80 * @return a list of elements that consist of tuples of the intersected
81 * gauges of the selected river.
82 */
83 @Override
84 protected Element[] createItems(
85 XMLUtils.ElementCreator cr,
86 Artifact artifact,
87 String name,
88 CallContext context)
89 {
90 logger.debug("WQAdapted.createItems");
91
92 if (name != null && name.equals(FIELD_WQ_MODE)) {
93 return createModeItems(cr, artifact, name, context);
94 }
95 else if (name != null && name.equals(FIELD_WQ_VALUES)) {
96 return createValueItems(cr, artifact, name, context);
97 }
98 else {
99 logger.warn("Unknown data object: " + name);
100 return null;
101 }
102 }
103
104
105 /** Creates "Q" and "W" items. */
106 protected Element[] createModeItems(
107 XMLUtils.ElementCreator cr,
108 Artifact artifact,
109 String name,
110 CallContext context)
111 {
112 logger.debug("WQAdapted.createModeItems");
113
114 Element w = createItem(cr, new String[] { "w", "W" });
115 Element q = createItem(cr, new String[] { "q", "Q" });
116
117 return new Element[] { w, q };
118 }
119
120
121 /** Create the items for input to the ranges per mode. */
122 protected Element[] createValueItems(
123 XMLUtils.ElementCreator cr,
124 Artifact artifact,
125 String name,
126 CallContext context)
127 {
128 logger.debug("WQAdapted.createValueItems");
129
130 FLYSArtifact flysArtifact = (FLYSArtifact) artifact;
131
132 RangeAccess rangeAccess = new RangeAccess(flysArtifact, context);
133 double[] dist = rangeAccess.getKmRange();
134 // TODO use Access to get River and gauges.
135 River river = FLYSUtils.getRiver(flysArtifact);
136 Wst wst = WstFactory.getWst(river);
137 List<Gauge> gauges = FLYSUtils.getGauges(flysArtifact);
138
139 int num = gauges != null ? gauges.size() : 0;
140
141 if (num == 0) {
142 logger.warn("Selected distance matches no gauges.");
143 return null;
144 }
145
146 List<Element> elements = new ArrayList<Element>();
147
148 double rangeFrom = dist[0];
149 double rangeTo = dist[1];
150
151 if (rangeFrom < rangeTo) {
152 Collections.sort(gauges, GAUGE_UP);
153 for (Gauge gauge: gauges) {
154 Range range = gauge.getRange();
155 double lower = range.getA().doubleValue();
156 double upper = range.getB().doubleValue();
157
158 // If gauge out of range, skip it.
159 if (upper <= rangeFrom || lower >= rangeTo) {
160 continue;
161 }
162
163 double from = lower < rangeFrom ? rangeFrom : lower;
164 double to = upper > rangeTo ? rangeTo : upper;
165
166 double[] mmQ = determineMinMaxQ(gauge, wst);
167 double[] mmW = gauge.determineMinMaxW();
168
169 elements.add(createItem(
170 cr, new String[] { from + ";" + to, gauge.getName()}, mmQ, mmW));
171 }
172 }
173 else {
174 Collections.sort(gauges, GAUGE_DOWN);
175 rangeFrom = dist[1];
176 rangeTo = dist[0];
177 for (Gauge gauge: gauges) {
178 Range range = gauge.getRange();
179 double lower = range.getA().doubleValue();
180 double upper = range.getB().doubleValue();
181
182 double from = lower < rangeFrom ? rangeFrom : lower;
183 double to = upper > rangeTo ? rangeTo : upper;
184
185 // TODO probably need to continue out if oof range (see above).
186
187 double[] mmQ = determineMinMaxQ(gauge, wst);
188 double[] mmW = gauge.determineMinMaxW();
189
190 elements.add(createItem(
191 cr, new String[] { to + ";" + from, gauge.getName()}, mmQ, mmW));
192 }
193 }
194
195 Element[] els = new Element[elements.size()];
196 return elements.toArray(els);
197 }
198
199
200 protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
201 return createItem(cr, obj, null, null);
202 }
203
204
205 /** In obj: 0 is label, 1 is value. */
206 protected Element createItem(
207 XMLUtils.ElementCreator cr,
208 Object obj,
209 double[] q,
210 double[] w)
211 {
212 Element item = ProtocolUtils.createArtNode(cr, "item", null, null);
213 Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
214 Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
215
216 String[] arr = (String[]) obj;
217
218 label.setTextContent(arr[0]);
219 value.setTextContent(arr[1]);
220
221 item.appendChild(label);
222 item.appendChild(value);
223
224 if (q != null) {
225 Element qRange = createRangeElement(cr, q, "Q");
226 item.appendChild(qRange);
227 }
228
229 if (w != null) {
230 Element wRange = createRangeElement(cr, w, "W");
231 item.appendChild(wRange);
232 }
233
234 return item;
235 }
236
237
238 protected Element createRangeElement(
239 XMLUtils.ElementCreator cr,
240 double[] mm,
241 String type)
242 {
243 Element range = ProtocolUtils.createArtNode(
244 cr, "range",
245 new String[] {"type"},
246 new String[] {type});
247
248 Element min = ProtocolUtils.createArtNode(cr, "min", null, null);
249 min.setTextContent(String.valueOf(mm[0]));
250
251 Element max = ProtocolUtils.createArtNode(cr, "max", null, null);
252 max.setTextContent(String.valueOf(mm[1]));
253
254 range.appendChild(min);
255 range.appendChild(max);
256
257 return range;
258 }
259
260
261 /**
262 * Determines the min and max Q value for the given gauge. If no min and
263 * max values could be determined, this method will return
264 * [Double.MIN_VALUE, Double.MAX_VALUE].
265 *
266 * @param gauge
267 * @param wst
268 *
269 * @return the min and max Q values for the given gauge.
270 */
271 protected double[] determineMinMaxQ(Gauge gauge, Wst wst) {
272 logger.debug("WQAdapted.determineMinMaxQ");
273
274 double[] minmaxQ = gauge != null
275 ? wst.determineMinMaxQ(gauge.getRange())
276 : null;
277
278 double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE;
279 double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE;
280
281 return new double[] { minQ, maxQ };
282 }
283
284
285 /** Indicate client which input elements to use. */
286 @Override
287 protected String getUIProvider() {
288 return "wq_panel_adapted";
289 }
290
291
292 @Override
293 public boolean validate(Artifact artifact)
294 throws IllegalArgumentException
295 {
296 logger.debug("WQAdapted.validate");
297
298 FLYSArtifact flys = (FLYSArtifact) artifact;
299 StateData data = getData(flys, FIELD_WQ_MODE);
300
301 String mode = data != null ? (String) data.getValue() : null;
302 boolean isQ = mode != null
303 ? Boolean.valueOf(mode)
304 : false;
305
306 if (!isQ) {
307 return validateW(artifact);
308 }
309 else if (isQ) {
310 return validateQ(artifact);
311 }
312 else {
313 throw new IllegalArgumentException("error_feed_no_wq_mode_selected");
314 }
315 }
316
317
318 protected boolean validateW(Artifact artifact)
319 throws IllegalArgumentException
320 {
321 logger.debug("WQAdapted.validateW");
322 FLYSArtifact flys = (FLYSArtifact) artifact;
323
324 RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));
325
326 if (rwvs == null) {
327 throw new IllegalArgumentException("error_missing_wq_data");
328 }
329
330 List<Gauge> gauges = FLYSUtils.getGauges((FLYSArtifact) artifact);
331
332 for (Gauge gauge: gauges) {
333 Range range = gauge.getRange();
334 double lower = range.getA().doubleValue();
335 double upper = range.getB().doubleValue();
336
337 for (RangeWithValues rwv: rwvs) {
338 if (lower <= rwv.getStart() && upper >= rwv.getEnd()) {
339 compareWsWithGauge(gauge, rwv.getValues());
340 }
341 }
342 }
343
344 return true;
345 }
346
347
348 protected boolean validateQ(Artifact artifact)
349 throws IllegalArgumentException
350 {
351 logger.debug("WQAdapted.validateQ");
352 FLYSArtifact flys = (FLYSArtifact) artifact;
353
354 RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));
355
356 if (rwvs == null) {
357 throw new IllegalArgumentException("error_missing_wq_data");
358 }
359
360 List<Gauge> gauges = FLYSUtils.getGauges(flys);
361 River river = FLYSUtils.getRiver(flys);
362 Wst wst = WstFactory.getWst(river);
363
364 for (Gauge gauge: gauges) {
365 Range range = gauge.getRange();
366 double lower = range.getA().doubleValue();
367 double upper = range.getB().doubleValue();
368
369 for (RangeWithValues rwv: rwvs) {
370 if (lower <= rwv.getStart() && upper >= rwv.getEnd()) {
371 compareQsWithGauge(wst, gauge, rwv.getValues());
372 }
373 }
374 }
375
376 return true;
377 }
378
379
380 protected boolean compareQsWithGauge(Wst wst, Gauge gauge, double[] qs)
381 throws IllegalArgumentException
382 {
383 double[] minmax = gauge != null
384 ? wst.determineMinMaxQ(gauge.getRange())
385 : null;
386
387 if (minmax == null) {
388 logger.warn("Could not determine min/max Q of gauge.");
389 return true;
390 }
391
392 if (logger.isDebugEnabled()) {
393 logger.debug("Validate Qs with:");
394 logger.debug("-- Gauge: " + gauge.getName());
395 logger.debug("-- Gauge min: " + minmax[0]);
396 logger.debug("-- Gauge max: " + minmax[1]);
397 }
398
399 for (double q: qs) {
400 if (q < minmax[0] || q > minmax[1]) {
401 throw new IllegalArgumentException(
402 "error_feed_q_values_invalid");
403 }
404 }
405
406 return true;
407 }
408
409
410 protected boolean compareWsWithGauge(Gauge gauge, double[] ws)
411 throws IllegalArgumentException
412 {
413 double[] minmax = gauge != null
414 ? gauge.determineMinMaxW()
415 : null;
416
417 if (minmax == null) {
418 logger.warn("Could not determine min/max W of gauge.");
419 return true;
420 }
421
422 if (logger.isDebugEnabled()) {
423 logger.debug("Validate Ws with:");
424 logger.debug("-- Gauge: " + gauge.getName());
425 logger.debug("-- Gauge min: " + minmax[0]);
426 logger.debug("-- Gauge max: " + minmax[1]);
427 }
428
429 for (double w: ws) {
430 if (w < minmax[0] || w > minmax[1]) {
431 throw new IllegalArgumentException(
432 "error_feed_w_values_invalid");
433 }
434 }
435
436 return true;
437 }
438
439
440 protected RangeWithValues[] extractInput(StateData data) {
441 if (data == null) {
442 return null;
443 }
444
445 String dataString = (String) data.getValue();
446 String[] ranges = dataString.split(":");
447
448 List<RangeWithValues> rwv = new ArrayList<RangeWithValues>();
449
450 for (String range: ranges) {
451 String[] parts = range.split(";");
452
453 double lower = Double.parseDouble(parts[0]);
454 double upper = Double.parseDouble(parts[1]);
455
456 String[] values = parts[3].split(",");
457
458 int num = values.length;
459 double[] res = new double[num];
460
461 for (int i = 0; i < num; i++) {
462 try {
463 res[i] = Double.parseDouble(values[i]);
464 }
465 catch (NumberFormatException nfe) {
466 logger.warn(nfe, nfe);
467 }
468 }
469
470 rwv.add(new RangeWithValues(lower, upper, res));
471 }
472
473 return rwv.toArray(new RangeWithValues[rwv.size()]);
474 }
475 }
476 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org