Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/org/dive4elements/river/artifacts/states/WQAdapted.java @ 5831:bd047b71ab37
Repaired internal references
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 12:06:39 +0200 |
parents | flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java@0ebadc678fbc |
children |
comparison
equal
deleted
inserted
replaced
5830:160f53ee0870 | 5831:bd047b71ab37 |
---|---|
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 : |