Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.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 | 72f77b2210c2 |
children | 938e2f6c0c9a |
comparison
equal
deleted
inserted
replaced
2456:60ab1054069d | 3818:dc18457b1cef |
---|---|
1 package de.intevation.flys.artifacts.model; | |
2 | |
3 import java.io.Serializable; | |
4 | |
5 import java.text.SimpleDateFormat; | |
6 | |
7 import java.util.ArrayList; | |
8 import java.util.Collections; | |
9 import java.util.Comparator; | |
10 import java.util.Date; | |
11 import java.util.HashMap; | |
12 import java.util.List; | |
13 import java.util.Map; | |
14 | |
15 import org.apache.log4j.Logger; | |
16 | |
17 import org.hibernate.SQLQuery; | |
18 import org.hibernate.Session; | |
19 | |
20 import org.hibernate.type.StandardBasicTypes; | |
21 | |
22 import org.w3c.dom.Document; | |
23 import org.w3c.dom.Element; | |
24 | |
25 public class FixingsOverview | |
26 implements Serializable | |
27 { | |
28 private static Logger log = Logger.getLogger(FixingsOverview.class); | |
29 | |
30 public static final double EPSILON = 1e-5; | |
31 public static final double EPSILON2 = 1e-1; | |
32 | |
33 public static final String DATE_FORMAT = "dd.MM.yyyy HH:mm"; | |
34 | |
35 public static final String SQL_RIVER_ID = | |
36 "SELECT" + | |
37 " id AS river_id," + | |
38 " km_up " + | |
39 "FROM rivers " + | |
40 "WHERE" + | |
41 " name = :name"; | |
42 | |
43 public static final String SQL_GAUGES = | |
44 "SELECT" + | |
45 " g.id AS gauge_id," + | |
46 " r.a AS a," + | |
47 " r.b AS b " + | |
48 "FROM gauges g" + | |
49 " JOIN ranges r ON g.range_id = r.id " + | |
50 "WHERE" + | |
51 " g.river_id = :river_id " + | |
52 "ORDER BY r.a"; | |
53 | |
54 public static final String SQL_DISCHARGE_SECTORS = | |
55 "SELECT" + | |
56 " g.id AS gauge_id," + | |
57 " nmv.name AS name," + | |
58 " CAST(mv.value AS NUMERIC(38,2)) AS value " + | |
59 "FROM gauges g" + | |
60 " JOIN main_values mv ON g.id = mv.gauge_id" + | |
61 " JOIN named_main_values nmv ON nmv.id = mv.named_value_id" + | |
62 " JOIN main_value_types mvt ON nmv.type_id = mvt.id " + | |
63 "WHERE" + | |
64 " mvt.name = 'Q' AND (" + | |
65 " nmv.name = 'MNQ' OR" + | |
66 " nmv.name LIKE 'MNQ(%' OR" + | |
67 " nmv.name = 'MQ' OR" + | |
68 " nmv.name LIKE 'MQ(%' OR" + | |
69 " nmv.name = 'MHQ' OR" + | |
70 " nmv.name LIKE 'MHQ(%' OR" + | |
71 " nmv.name = 'HQ5' OR" + | |
72 " nmv.name LIKE 'HQ5(%') AND" + | |
73 " g.river_id = :river_id " + | |
74 "ORDER BY" + | |
75 " g.id"; | |
76 | |
77 public static final String SQL_FIXINGS = | |
78 "SELECT" + | |
79 " id AS wst_id," + | |
80 " description " + | |
81 "FROM wsts " + | |
82 "WHERE" + | |
83 " river_id = :river_id AND kind = 2"; | |
84 | |
85 public static final String SQL_FIXING_COLUMNS = | |
86 "SELECT" + | |
87 " wc.id AS wst_column_id," + | |
88 " ti.start_time AS start_time," + | |
89 " wc.name AS name " + | |
90 "FROM wst_columns wc" + | |
91 " JOIN time_intervals ti ON wc.time_interval_id = ti.id " + | |
92 "WHERE" + | |
93 " wc.wst_id = :wst_id " + | |
94 "ORDER BY position"; | |
95 | |
96 public static final String SQL_FIXING_COLUMN_Q_RANGES = | |
97 "SELECT" + | |
98 " wqr.q AS q," + | |
99 " r.a AS start_km," + | |
100 " r.b AS stop_km " + | |
101 "FROM wst_column_q_ranges wcqr" + | |
102 " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" + | |
103 " JOIN ranges r ON wqr.range_id = r.id " + | |
104 "WHERE" + | |
105 " wcqr.wst_column_id = :column_id " + | |
106 "ORDER BY r.a"; | |
107 | |
108 public static final String SQL_FIXING_COLUMN_KM_RANGE = | |
109 "SELECT" + | |
110 " MIN(position) AS start_km," + | |
111 " MAX(position) AS stop_km " + | |
112 "FROM" + | |
113 " wst_column_values " + | |
114 "WHERE" + | |
115 " wst_column_id = :column_id"; | |
116 | |
117 public static class Range implements Serializable { | |
118 | |
119 protected double start; | |
120 protected double end; | |
121 | |
122 public Range() { | |
123 } | |
124 | |
125 public Range(double start, double end) { | |
126 this.start = start; | |
127 this.end = end; | |
128 } | |
129 | |
130 public double getStart() { | |
131 return start; | |
132 } | |
133 | |
134 public double getEnd() { | |
135 return end; | |
136 } | |
137 | |
138 public boolean disjoint(Range other) { | |
139 return start > other.end || other.start > end; | |
140 } | |
141 | |
142 public boolean intersects(Range other) { | |
143 return !disjoint(other); | |
144 } | |
145 | |
146 public void extend(Range other) { | |
147 if (other.start < start) start = other.start; | |
148 if (other.end > end ) end = other.end; | |
149 } | |
150 | |
151 public boolean clip(Range other) { | |
152 if (disjoint(other)) return false; | |
153 | |
154 if (other.start > start) start = other.start; | |
155 if (other.end < end ) end = other.end; | |
156 | |
157 return true; | |
158 } | |
159 | |
160 public boolean inside(double x) { | |
161 return x > start-EPSILON && x < end+EPSILON; | |
162 } | |
163 } // class Range | |
164 | |
165 public static class GaugeRange extends Range { | |
166 | |
167 private static final class Sector implements Serializable { | |
168 | |
169 int sector; | |
170 double value; | |
171 | |
172 Sector(int sector, double value) { | |
173 this.sector = sector; | |
174 this.value = value; | |
175 } | |
176 | |
177 } // class Sector | |
178 | |
179 protected int gaugeId; | |
180 | |
181 protected Map<String, Double> mainValues; | |
182 protected List<Sector> sectors; | |
183 | |
184 public GaugeRange() { | |
185 } | |
186 | |
187 public GaugeRange(double start, double end, int gaugeId) { | |
188 super(start, end); | |
189 this.gaugeId = gaugeId; | |
190 mainValues = new HashMap<String, Double>(); | |
191 sectors = new ArrayList<Sector>(3); | |
192 } | |
193 | |
194 public void addMainValue(String label, Double value) { | |
195 int idx = label.indexOf('('); | |
196 if (idx >= 0) { | |
197 label = label.substring(0, idx); | |
198 } | |
199 mainValues.put(label, value); | |
200 } | |
201 | |
202 protected Double getMainValue(String label) { | |
203 Double v = mainValues.get(label); | |
204 if (v == null) { | |
205 log.warn("Missing main value '" | |
206 + label + "' for gauge " + gaugeId); | |
207 } | |
208 return v; | |
209 } | |
210 | |
211 public void buildClasses() { | |
212 Double mnq = getMainValue("MNQ"); | |
213 Double mq = getMainValue("MQ"); | |
214 Double mhq = getMainValue("MHQ"); | |
215 Double hq5 = getMainValue("HQ5"); | |
216 | |
217 Double [][] pairs = { | |
218 { mnq, mq }, | |
219 { mq, mhq }, | |
220 { hq5, hq5 } }; | |
221 | |
222 for (int c = 0; c < pairs.length; ++c) { | |
223 Double [] pair = pairs[c]; | |
224 if (pair[0] != null && pair[1] != null) { | |
225 double value = 0.5*(pair[0] + pair[1]); | |
226 sectors.add(new Sector(c, value)); | |
227 } | |
228 } | |
229 } | |
230 | |
231 public int classify(double value) { | |
232 for (Sector sector: sectors) { | |
233 if (value < sector.value) { | |
234 return sector.sector; | |
235 } | |
236 } | |
237 return sectors.size(); | |
238 } | |
239 } // class GaugeRange | |
240 | |
241 public static class GaugeFinder { | |
242 | |
243 protected List<GaugeRange> gauges; | |
244 protected boolean isKmUp; | |
245 | |
246 public GaugeFinder(List<GaugeRange> gauges) { | |
247 this(gauges, true); | |
248 } | |
249 | |
250 public GaugeFinder( | |
251 List<GaugeRange> gauges, | |
252 boolean isKmUp | |
253 ) { | |
254 this.gauges = gauges; | |
255 this.isKmUp = isKmUp; | |
256 } | |
257 | |
258 public boolean getIsKmUp() { | |
259 return isKmUp; | |
260 } | |
261 | |
262 public void setIsKmUp(boolean isKmUp) { | |
263 this.isKmUp = isKmUp; | |
264 } | |
265 | |
266 public GaugeRange find(Range range) { | |
267 double km = isKmUp ? range.start : range.end; | |
268 for (GaugeRange gauge: gauges) { | |
269 if (gauge.inside(km)) { | |
270 return gauge; | |
271 } | |
272 } | |
273 return null; | |
274 } | |
275 | |
276 public GaugeRange find(int gaugeId) { | |
277 for (GaugeRange gauge: gauges) { | |
278 if (gauge.gaugeId == gaugeId) { | |
279 return gauge; | |
280 } | |
281 } | |
282 return null; | |
283 } | |
284 | |
285 public boolean loadDischargeSectors(Session session, int riverId) { | |
286 | |
287 SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS) | |
288 .addScalar("gauge_id", StandardBasicTypes.INTEGER) | |
289 .addScalar("name", StandardBasicTypes.STRING) | |
290 .addScalar("value", StandardBasicTypes.DOUBLE); | |
291 | |
292 query.setInteger("river_id", riverId); | |
293 | |
294 List<Object []> list = query.list(); | |
295 | |
296 if (list.isEmpty()) { | |
297 log.warn("River " + riverId + " has no discharge sectors."); | |
298 return false; | |
299 } | |
300 | |
301 GaugeRange gauge = null; | |
302 | |
303 for (Object [] row: list) { | |
304 int gaugeId = (Integer)row[0]; | |
305 String label = (String) row[1]; | |
306 Double value = (Double) row[2]; | |
307 | |
308 if (gauge == null || gauge.gaugeId != gaugeId) { | |
309 if ((gauge = find(gaugeId)) == null) { | |
310 log.warn("Cannot find gauge for id " + gaugeId + "."); | |
311 continue; | |
312 } | |
313 } | |
314 | |
315 gauge.addMainValue(label, value); | |
316 } | |
317 | |
318 for (GaugeRange g: gauges) { | |
319 g.buildClasses(); | |
320 } | |
321 | |
322 return true; | |
323 } | |
324 } // class GaugeFinder | |
325 | |
326 public static class QRange extends Range { | |
327 | |
328 protected double q; | |
329 | |
330 public QRange() { | |
331 } | |
332 | |
333 public QRange(double start, double end, double q) { | |
334 super(start, end); | |
335 this.q = q; | |
336 } | |
337 } // class QRange | |
338 | |
339 public static class SectorRange extends Range { | |
340 | |
341 protected int sector; | |
342 | |
343 public SectorRange() { | |
344 } | |
345 | |
346 public SectorRange(SectorRange other) { | |
347 start = other.start; | |
348 end = other.end; | |
349 sector = other.sector; | |
350 } | |
351 | |
352 public SectorRange(double start, double end, int sector) { | |
353 super(start, end); | |
354 this.sector = sector; | |
355 } | |
356 | |
357 public int getSector() { | |
358 return sector; | |
359 } | |
360 | |
361 public boolean enlarge(SectorRange other) { | |
362 if (sector == other.sector | |
363 && Math.abs(end-other.start) < EPSILON2) { | |
364 end = other.end; | |
365 return true; | |
366 } | |
367 return false; | |
368 } | |
369 } // class SectorRange | |
370 | |
371 public static class Fixing implements Serializable { | |
372 | |
373 public static final Comparator<Column> DATE_CMP = | |
374 new Comparator<Column>() { | |
375 @Override | |
376 public int compare(Column a, Column b) { | |
377 return a.startTime.compareTo(b.startTime); | |
378 } | |
379 }; | |
380 | |
381 public interface Filter { | |
382 | |
383 boolean accept(Column column); | |
384 | |
385 } // interface Filter | |
386 | |
387 public class Column extends Range { | |
388 | |
389 protected int columnId; | |
390 protected Date startTime; | |
391 protected String name; | |
392 | |
393 protected List<SectorRange> sectors; | |
394 | |
395 public Column() { | |
396 } | |
397 | |
398 public Column(int columnId, Date startTime, String name) { | |
399 this.columnId = columnId; | |
400 this.startTime = startTime; | |
401 this.name = name; | |
402 | |
403 sectors = new ArrayList<SectorRange>(); | |
404 } | |
405 | |
406 public int getId() { | |
407 return columnId; | |
408 } | |
409 | |
410 public Fixing getFixing() { | |
411 return Fixing.this; | |
412 } | |
413 | |
414 public Date getStartTime() { | |
415 return startTime; | |
416 } | |
417 | |
418 public String getName() { | |
419 return name; | |
420 } | |
421 | |
422 public List<SectorRange> getSectors() { | |
423 return sectors; | |
424 } | |
425 | |
426 public List<SectorRange> getSectors(Range range) { | |
427 | |
428 List<SectorRange> result = | |
429 new ArrayList<SectorRange>(sectors.size()); | |
430 | |
431 for (SectorRange src: sectors) { | |
432 SectorRange dst = new SectorRange(src); | |
433 if (dst.clip(range)) { | |
434 result.add(dst); | |
435 } | |
436 } | |
437 | |
438 return result; | |
439 } | |
440 | |
441 public void buildSectors(GaugeRange gauge, List<QRange> qRanges) { | |
442 | |
443 for (QRange qRange: qRanges) { | |
444 SectorRange sector = new SectorRange( | |
445 qRange.start, qRange.end, | |
446 gauge.classify(qRange.q)); | |
447 if (sectors.isEmpty() | |
448 || !sectors.get(sectors.size()-1).enlarge(sector)) { | |
449 sectors.add(sector); | |
450 } | |
451 } | |
452 } | |
453 | |
454 public void loadKmRange(SQLQuery query) { | |
455 query.setInteger("column_id", columnId); | |
456 | |
457 List<Object []> kms = query.list(); | |
458 | |
459 if (kms.isEmpty()) { | |
460 log.warn("No km range for column " + columnId + "."); | |
461 } | |
462 else { | |
463 Object [] obj = kms.get(0); | |
464 start = (Double)obj[0]; | |
465 end = (Double)obj[1]; | |
466 } | |
467 } | |
468 | |
469 public void loadQRanges( | |
470 SQLQuery query, | |
471 GaugeFinder gaugeFinder | |
472 ) { | |
473 query.setInteger("column_id", columnId); | |
474 List<Object []> list = query.list(); | |
475 | |
476 List<QRange> qRanges = new ArrayList<QRange>(list.size()); | |
477 | |
478 for (Object [] row: list) { | |
479 double q = (Double)row[0]; | |
480 double start = (Double)row[1]; | |
481 double end = (Double)row[2]; | |
482 QRange qRange = new QRange(start, end, q); | |
483 if (qRange.clip(this)) { | |
484 qRanges.add(qRange); | |
485 } | |
486 } | |
487 | |
488 GaugeRange gauge = gaugeFinder.find(this); | |
489 | |
490 if (gauge != null) { | |
491 buildSectors(gauge, qRanges); | |
492 } | |
493 else { | |
494 log.warn("No gauge found for column " + columnId + "."); | |
495 } | |
496 } | |
497 } // class Column | |
498 | |
499 protected int wstId; | |
500 protected String description; | |
501 protected List<Column> columns; | |
502 | |
503 public Fixing() { | |
504 } | |
505 | |
506 public int getId() { | |
507 return wstId; | |
508 } | |
509 | |
510 public String getDescription() { | |
511 return description; | |
512 } | |
513 | |
514 public Fixing(int wstId, String description) { | |
515 this.wstId = wstId; | |
516 this.description = description; | |
517 columns = new ArrayList<Column>(); | |
518 } | |
519 | |
520 public void loadColumns(SQLQuery query) { | |
521 query.setInteger("wst_id", wstId); | |
522 List<Object []> list = query.list(); | |
523 for (Object [] row: list) { | |
524 int columnId = (Integer)row[0]; | |
525 Date startTime = (Date) row[1]; | |
526 String name = (String) row[2]; | |
527 columns.add(new Column(columnId, startTime, name)); | |
528 } | |
529 } | |
530 | |
531 public void loadColumnsKmRange(SQLQuery query) { | |
532 for (Column column: columns) { | |
533 column.loadKmRange(query); | |
534 } | |
535 } | |
536 | |
537 public void adjustExtent(Range extent) { | |
538 for (Column column: columns) { | |
539 extent.extend(column); | |
540 } | |
541 } | |
542 | |
543 public void loadColumnsQRanges( | |
544 SQLQuery query, | |
545 GaugeFinder gaugeFinder | |
546 ) { | |
547 for (Column column: columns) { | |
548 column.loadQRanges(query, gaugeFinder); | |
549 } | |
550 } | |
551 | |
552 public void addAllColumns( | |
553 List<Column> allColumns, | |
554 Range range, | |
555 Filter filter | |
556 ) { | |
557 for (Column column: columns) { | |
558 if (column.intersects(range) && filter.accept(column)) { | |
559 allColumns.add(column); | |
560 } | |
561 } | |
562 } | |
563 } // class Fixing | |
564 | |
565 | |
566 protected String riverName; | |
567 protected int riverId; | |
568 protected boolean isKmUp; | |
569 protected List<Fixing> fixings; | |
570 protected Range extent; | |
571 | |
572 public FixingsOverview() { | |
573 fixings = new ArrayList<Fixing>(); | |
574 extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); | |
575 } | |
576 | |
577 public FixingsOverview(String riverName) { | |
578 this(); | |
579 this.riverName = riverName; | |
580 } | |
581 | |
582 protected boolean loadRiver(Session session) { | |
583 SQLQuery query = session.createSQLQuery(SQL_RIVER_ID) | |
584 .addScalar("river_id", StandardBasicTypes.INTEGER) | |
585 .addScalar("km_up", StandardBasicTypes.BOOLEAN); | |
586 | |
587 query.setString("name", riverName); | |
588 | |
589 List<Object []> list = query.list(); | |
590 | |
591 if (list.isEmpty()) { | |
592 log.warn("No river '" + riverName + "' found."); | |
593 return false; | |
594 } | |
595 | |
596 Object [] row = list.get(0); | |
597 | |
598 riverId = (Integer)row[0]; | |
599 isKmUp = (Boolean)row[1]; | |
600 | |
601 return true; | |
602 } | |
603 | |
604 protected GaugeFinder loadGauges(Session session) { | |
605 SQLQuery query = session.createSQLQuery(SQL_GAUGES) | |
606 .addScalar("gauge_id", StandardBasicTypes.INTEGER) | |
607 .addScalar("a", StandardBasicTypes.DOUBLE) | |
608 .addScalar("b", StandardBasicTypes.DOUBLE); | |
609 | |
610 query.setInteger("river_id", riverId); | |
611 | |
612 List<Object []> list = query.list(); | |
613 | |
614 if (list.isEmpty()) { | |
615 log.warn("River " + riverId + " has no gauges."); | |
616 return null; | |
617 } | |
618 | |
619 List<GaugeRange> gauges = new ArrayList<GaugeRange>(); | |
620 | |
621 for (Object [] row: list) { | |
622 int gaugeId = (Integer)row[0]; | |
623 double start = (Double) row[1]; | |
624 double end = (Double) row[2]; | |
625 GaugeRange gauge = new GaugeRange(start, end, gaugeId); | |
626 gauges.add(gauge); | |
627 } | |
628 | |
629 return new GaugeFinder(gauges, isKmUp); | |
630 } | |
631 | |
632 | |
633 protected void loadFixings(Session session) { | |
634 SQLQuery query = session.createSQLQuery(SQL_FIXINGS) | |
635 .addScalar("wst_id", StandardBasicTypes.INTEGER) | |
636 .addScalar("description", StandardBasicTypes.STRING); | |
637 | |
638 query.setInteger("river_id", riverId); | |
639 | |
640 List<Object []> list = query.list(); | |
641 | |
642 if (list.isEmpty()) { | |
643 log.warn("River " + riverId + " has no fixings."); | |
644 // Its pretty fine to have no fixings. | |
645 } | |
646 | |
647 for (Object [] row: list) { | |
648 int wstId = (Integer)row[0]; | |
649 String description = (String) row[1]; | |
650 Fixing fixing = new Fixing(wstId, description); | |
651 fixings.add(fixing); | |
652 } | |
653 } | |
654 | |
655 protected void loadFixingsColumns(Session session) { | |
656 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS) | |
657 .addScalar("wst_column_id", StandardBasicTypes.INTEGER) | |
658 .addScalar("start_time", StandardBasicTypes.DATE) | |
659 .addScalar("name", StandardBasicTypes.STRING); | |
660 | |
661 for (Fixing fixing: fixings) { | |
662 fixing.loadColumns(query); | |
663 } | |
664 } | |
665 | |
666 protected void loadFixingsColumnsKmRange(Session session) { | |
667 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE) | |
668 .addScalar("start_km", StandardBasicTypes.DOUBLE) | |
669 .addScalar("stop_km", StandardBasicTypes.DOUBLE); | |
670 | |
671 for (Fixing fixing: fixings) { | |
672 fixing.loadColumnsKmRange(query); | |
673 } | |
674 } | |
675 | |
676 protected void loadFixingsColumnsQRanges( | |
677 Session session, | |
678 GaugeFinder gaugeFinder | |
679 ) { | |
680 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) | |
681 .addScalar("q", StandardBasicTypes.DOUBLE) | |
682 .addScalar("start_km", StandardBasicTypes.DOUBLE) | |
683 .addScalar("stop_km", StandardBasicTypes.DOUBLE); | |
684 | |
685 for (Fixing fixing: fixings) { | |
686 fixing.loadColumnsQRanges(query, gaugeFinder); | |
687 } | |
688 } | |
689 | |
690 protected void adjustExtent() { | |
691 for (Fixing fixing: fixings) { | |
692 fixing.adjustExtent(extent); | |
693 } | |
694 } | |
695 | |
696 public boolean load(Session session) { | |
697 | |
698 if (!loadRiver(session)) { | |
699 return false; | |
700 } | |
701 | |
702 GaugeFinder gaugeFinder = loadGauges(session); | |
703 | |
704 if (gaugeFinder == null | |
705 || !gaugeFinder.loadDischargeSectors(session, riverId)) { | |
706 return false; | |
707 } | |
708 | |
709 loadFixings(session); | |
710 loadFixingsColumns(session); | |
711 loadFixingsColumnsKmRange(session); | |
712 | |
713 adjustExtent(); | |
714 | |
715 loadFixingsColumnsQRanges(session, gaugeFinder); | |
716 | |
717 return true; | |
718 } | |
719 | |
720 public static final Range FULL_EXTENT = | |
721 new Range(-Double.MAX_VALUE, Double.MAX_VALUE); | |
722 | |
723 public static final Fixing.Filter ACCEPT = new Fixing.Filter() { | |
724 @Override | |
725 public boolean accept(Fixing.Column column) { | |
726 return true; | |
727 } | |
728 }; | |
729 | |
730 public static class NotFilter implements Fixing.Filter { | |
731 protected Fixing.Filter child; | |
732 | |
733 public NotFilter(Fixing.Filter child) { | |
734 this.child = child; | |
735 } | |
736 | |
737 @Override | |
738 public boolean accept(Fixing.Column column) { | |
739 return !child.accept(column); | |
740 } | |
741 } // class NotFilter | |
742 | |
743 public static abstract class ComponentFilter implements Fixing.Filter { | |
744 protected List<Fixing.Filter> children; | |
745 | |
746 public ComponentFilter(List<Fixing.Filter> children) { | |
747 this.children = children; | |
748 } | |
749 } // class ComponentFilter | |
750 | |
751 public static class OrFilter extends ComponentFilter { | |
752 | |
753 public OrFilter(List<Fixing.Filter> children) { | |
754 super(children); | |
755 } | |
756 | |
757 @Override | |
758 public boolean accept(Fixing.Column column) { | |
759 for (Fixing.Filter child: children) { | |
760 if (child.accept(column)) { | |
761 return true; | |
762 } | |
763 } | |
764 return false; | |
765 } | |
766 } // class OrFilter | |
767 | |
768 public static class AndFilter extends ComponentFilter { | |
769 | |
770 public AndFilter(List<Fixing.Filter> children) { | |
771 super(children); | |
772 } | |
773 | |
774 @Override | |
775 public boolean accept(Fixing.Column column) { | |
776 for (Fixing.Filter child: children) { | |
777 if (!child.accept(column)) { | |
778 return false; | |
779 } | |
780 } | |
781 return true; | |
782 } | |
783 } // class AndFilter | |
784 | |
785 public static class IdFilter implements Fixing.Filter { | |
786 | |
787 protected int columnId; | |
788 | |
789 public IdFilter(int columnId) { | |
790 this.columnId = columnId; | |
791 } | |
792 | |
793 @Override | |
794 public boolean accept(Fixing.Column column) { | |
795 return column.getId() == columnId; | |
796 } | |
797 } // class IdFilter | |
798 | |
799 public static class DateFilter implements Fixing.Filter { | |
800 | |
801 protected Date date; | |
802 | |
803 public DateFilter(Date date) { | |
804 this.date = date; | |
805 } | |
806 | |
807 @Override | |
808 public boolean accept(Fixing.Column column) { | |
809 return date.equals(column.getStartTime()); | |
810 } | |
811 } // class DateFilter | |
812 | |
813 public static class DateRangeFilter implements Fixing.Filter { | |
814 | |
815 protected Date start; | |
816 protected Date end; | |
817 | |
818 public DateRangeFilter(Date start, Date end) { | |
819 this.start = start; | |
820 this.end = end; | |
821 } | |
822 | |
823 @Override | |
824 public boolean accept(Fixing.Column column) { | |
825 Date date = column.getStartTime(); | |
826 return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; | |
827 } | |
828 } // class DateRangeFilter | |
829 | |
830 public static class SectorRangeFilter implements Fixing.Filter { | |
831 | |
832 protected int min; | |
833 protected int max; | |
834 | |
835 public SectorRangeFilter(int min, int max) { | |
836 this.min = Math.min(min, max); | |
837 this.max = Math.max(min, max); | |
838 } | |
839 | |
840 @Override | |
841 public boolean accept(Fixing.Column column) { | |
842 for (SectorRange s: column.getSectors()) { | |
843 int v = s.getSector(); | |
844 if (v >= min && v <= max) { | |
845 return true; | |
846 } | |
847 } | |
848 return false; | |
849 } | |
850 } // class SectorRangeFilter | |
851 | |
852 public void generateOverview(Document document) { | |
853 generateOverview(document, FULL_EXTENT, ACCEPT); | |
854 } | |
855 | |
856 public void generateOverview( | |
857 Document document, | |
858 Range range, | |
859 Fixing.Filter filter | |
860 ) { | |
861 List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); | |
862 | |
863 for (Fixing fixing: fixings) { | |
864 fixing.addAllColumns(allColumns, range, filter); | |
865 } | |
866 | |
867 Collections.sort(allColumns, Fixing.DATE_CMP); | |
868 | |
869 Element fixingsElement = document.createElement("fixings"); | |
870 | |
871 Element riverElement = document.createElement("river"); | |
872 | |
873 riverElement.setAttribute("from", String.valueOf(extent.start)); | |
874 riverElement.setAttribute("to", String.valueOf(extent.end)); | |
875 riverElement.setAttribute("rid", String.valueOf(riverId)); | |
876 riverElement.setAttribute("name", riverName); | |
877 | |
878 fixingsElement.appendChild(riverElement); | |
879 | |
880 SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); | |
881 | |
882 Element esE = document.createElement("events"); | |
883 | |
884 for (Fixing.Column column: allColumns) { | |
885 | |
886 List<SectorRange> sectors = column.getSectors(range); | |
887 | |
888 if (!sectors.isEmpty()) { | |
889 Element eE = document.createElement("event"); | |
890 eE.setAttribute("name", | |
891 String.valueOf(column.getFixing().description)); | |
892 eE.setAttribute("cid", String.valueOf(column.columnId)); | |
893 eE.setAttribute("date", df.format(column.startTime)); | |
894 | |
895 for (SectorRange sector: sectors) { | |
896 Element sE = document.createElement("sector"); | |
897 | |
898 sE.setAttribute("from", String.valueOf(sector.start)); | |
899 sE.setAttribute("to", String.valueOf(sector.end)); | |
900 sE.setAttribute("class", String.valueOf(sector.sector)); | |
901 | |
902 eE.appendChild(sE); | |
903 } | |
904 | |
905 esE.appendChild(eE); | |
906 } | |
907 } | |
908 | |
909 fixingsElement.appendChild(esE); | |
910 | |
911 document.appendChild(fixingsElement); | |
912 } | |
913 } | |
914 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |