comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java @ 3318:dbe2f85bf160

merged flys-artifacts/2.8
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:35 +0200
parents 29022c93027d
children 086326be721c
comparison
equal deleted inserted replaced
2987:98c7a46ec5ae 3318:dbe2f85bf160
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.List;
12
13 import org.apache.log4j.Logger;
14
15 import org.hibernate.SQLQuery;
16 import org.hibernate.Session;
17
18 import org.hibernate.type.StandardBasicTypes;
19
20 import org.w3c.dom.Document;
21 import org.w3c.dom.Element;
22
23 public class FixingsOverview
24 implements Serializable
25 {
26 private static Logger log = Logger.getLogger(FixingsOverview.class);
27
28 public static final double EPSILON = 1e-1;
29
30 public static final String DATE_FORMAT = "dd.MM.yyyy";
31
32 public static final String SQL_RIVER_ID =
33 "SELECT" +
34 " id AS river_id," +
35 " km_up " +
36 "FROM rivers " +
37 "WHERE" +
38 " name = :name";
39
40 public static final String SQL_FIXINGS =
41 "SELECT" +
42 " id AS wst_id," +
43 " description " +
44 "FROM wsts " +
45 "WHERE" +
46 " river_id = :river_id AND kind = 2";
47
48 public static final String SQL_FIXING_COLUMNS =
49 "SELECT" +
50 " wc.id AS wst_column_id," +
51 " ti.start_time AS start_time," +
52 " wc.name AS name " +
53 "FROM wst_columns wc" +
54 " JOIN time_intervals ti ON wc.time_interval_id = ti.id " +
55 "WHERE" +
56 " wc.wst_id = :wst_id " +
57 "ORDER BY position";
58
59 public static final String SQL_FIXING_COLUMN_Q_RANGES =
60 "SELECT" +
61 " wqr.q AS q," +
62 " r.a AS start_km," +
63 " r.b AS stop_km " +
64 "FROM wst_column_q_ranges wcqr" +
65 " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" +
66 " JOIN ranges r ON wqr.range_id = r.id " +
67 "WHERE" +
68 " wcqr.wst_column_id = :column_id " +
69 "ORDER BY r.a";
70
71 public static final String SQL_FIXING_COLUMN_KM_RANGE =
72 "SELECT" +
73 " MIN(position) AS start_km," +
74 " MAX(position) AS stop_km " +
75 "FROM" +
76 " wst_column_values " +
77 "WHERE" +
78 " wst_column_id = :column_id";
79
80
81
82 public static class QRange extends Range {
83
84 protected double q;
85
86 public QRange() {
87 }
88
89 public QRange(double start, double end, double q) {
90 super(start, end);
91 this.q = q;
92 }
93 } // class QRange
94
95 public static class SectorRange extends Range {
96
97 protected int sector;
98
99 public SectorRange() {
100 }
101
102 public SectorRange(SectorRange other) {
103 start = other.start;
104 end = other.end;
105 sector = other.sector;
106 }
107
108 public SectorRange(double start, double end, int sector) {
109 super(start, end);
110 this.sector = sector;
111 }
112
113 public int getSector() {
114 return sector;
115 }
116
117 public boolean enlarge(SectorRange other) {
118 if (sector == other.sector
119 && Math.abs(end-other.start) < EPSILON) {
120 end = other.end;
121 return true;
122 }
123 return false;
124 }
125 } // class SectorRange
126
127 public static class Fixing implements Serializable {
128
129 public static final Comparator<Column> DATE_CMP =
130 new Comparator<Column>() {
131 @Override
132 public int compare(Column a, Column b) {
133 return a.startTime.compareTo(b.startTime);
134 }
135 };
136
137 public interface Filter {
138
139 boolean accept(Column column);
140
141 } // interface Filter
142
143 public class Column extends Range {
144
145 protected int columnId;
146 protected Date startTime;
147 protected String name;
148
149 protected List<SectorRange> sectors;
150
151 public Column() {
152 }
153
154 public Column(int columnId, Date startTime, String name) {
155 this.columnId = columnId;
156 this.startTime = startTime;
157 this.name = name;
158
159 sectors = new ArrayList<SectorRange>();
160 }
161
162 public int getId() {
163 return columnId;
164 }
165
166 public Fixing getFixing() {
167 return Fixing.this;
168 }
169
170 public Date getStartTime() {
171 return startTime;
172 }
173
174 public String getName() {
175 return name;
176 }
177
178 public String getDescription() {
179 return Fixing.this.description + "/" + name;
180 }
181
182 public List<SectorRange> getSectors() {
183 return sectors;
184 }
185
186 public List<SectorRange> getSectors(Range range) {
187
188 List<SectorRange> result =
189 new ArrayList<SectorRange>(sectors.size());
190
191 for (SectorRange src: sectors) {
192 SectorRange dst = new SectorRange(src);
193 if (range == null || dst.clip(range)) {
194 result.add(dst);
195 }
196 }
197
198 return result;
199 }
200
201 public int findQSector(double km) {
202 for (SectorRange sector: sectors) {
203 if (sector.inside(km)) {
204 return sector.getSector();
205 }
206 }
207 return -1;
208 }
209
210 public void buildSectors(GaugeRange gauge, List<QRange> qRanges) {
211
212 for (QRange qRange: qRanges) {
213 SectorRange sector = new SectorRange(
214 qRange.start, qRange.end,
215 gauge.classify(qRange.q));
216 if (sectors.isEmpty()
217 || !sectors.get(sectors.size()-1).enlarge(sector)) {
218 sectors.add(sector);
219 }
220 }
221 }
222
223 public void loadKmRange(SQLQuery query) {
224 query.setInteger("column_id", columnId);
225
226 List<Object []> kms = query.list();
227
228 if (kms.isEmpty()) {
229 log.warn("No km range for column " + columnId + ".");
230 }
231 else {
232 Object [] obj = kms.get(0);
233 start = (Double)obj[0];
234 end = (Double)obj[1];
235 }
236 }
237
238 public void loadQRanges(
239 SQLQuery query,
240 GaugeFinder gaugeFinder
241 ) {
242 query.setInteger("column_id", columnId);
243 List<Object []> list = query.list();
244
245 List<QRange> qRanges = new ArrayList<QRange>(list.size());
246
247 for (Object [] row: list) {
248 double q = (Double)row[0];
249 double start = (Double)row[1];
250 double end = (Double)row[2];
251 QRange qRange = new QRange(start, end, q);
252 if (qRange.clip(this)) {
253 qRanges.add(qRange);
254 }
255 }
256
257 GaugeRange gauge = gaugeFinder.find(this);
258
259 if (gauge != null) {
260 buildSectors(gauge, qRanges);
261 }
262 else {
263 log.warn("No gauge found for column " + columnId + ".");
264 }
265 }
266 } // class Column
267
268 protected int wstId;
269 protected String description;
270 protected List<Column> columns;
271
272 public Fixing() {
273 }
274
275 public int getId() {
276 return wstId;
277 }
278
279 public String getDescription() {
280 return description;
281 }
282
283 public Fixing(int wstId, String description) {
284 this.wstId = wstId;
285 this.description = description;
286 columns = new ArrayList<Column>();
287 }
288
289 public void loadColumns(SQLQuery query) {
290 query.setInteger("wst_id", wstId);
291 List<Object []> list = query.list();
292 for (Object [] row: list) {
293 int columnId = (Integer)row[0];
294 Date startTime = (Date) row[1];
295 String name = (String) row[2];
296 columns.add(new Column(columnId, startTime, name));
297 }
298 }
299
300 public void loadColumnsKmRange(SQLQuery query) {
301 for (Column column: columns) {
302 column.loadKmRange(query);
303 }
304 }
305
306 public void adjustExtent(Range extent) {
307 for (Column column: columns) {
308 extent.extend(column);
309 }
310 }
311
312 public void loadColumnsQRanges(
313 SQLQuery query,
314 GaugeFinder gaugeFinder
315 ) {
316 for (Column column: columns) {
317 column.loadQRanges(query, gaugeFinder);
318 }
319 }
320
321 public void addAllColumns(
322 List<Column> allColumns,
323 Range range,
324 Filter filter
325 ) {
326 for (Column column: columns) {
327 if ((range == null || column.intersects(range))
328 && (filter == null || filter.accept(column))) {
329 allColumns.add(column);
330 }
331 }
332 }
333 } // class Fixing
334
335
336 protected String riverName;
337 protected int riverId;
338 protected boolean isKmUp;
339 protected List<Fixing> fixings;
340 protected Range extent;
341
342 public FixingsOverview() {
343 fixings = new ArrayList<Fixing>();
344 extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE);
345 }
346
347 public FixingsOverview(String riverName) {
348 this();
349 this.riverName = riverName;
350 }
351
352 protected boolean loadRiver(Session session) {
353 SQLQuery query = session.createSQLQuery(SQL_RIVER_ID)
354 .addScalar("river_id", StandardBasicTypes.INTEGER)
355 .addScalar("km_up", StandardBasicTypes.BOOLEAN);
356
357 query.setString("name", riverName);
358
359 List<Object []> list = query.list();
360
361 if (list.isEmpty()) {
362 log.warn("No river '" + riverName + "' found.");
363 return false;
364 }
365
366 Object [] row = list.get(0);
367
368 riverId = (Integer)row[0];
369 isKmUp = (Boolean)row[1];
370
371 return true;
372 }
373
374 protected void loadFixings(Session session) {
375 SQLQuery query = session.createSQLQuery(SQL_FIXINGS)
376 .addScalar("wst_id", StandardBasicTypes.INTEGER)
377 .addScalar("description", StandardBasicTypes.STRING);
378
379 query.setInteger("river_id", riverId);
380
381 List<Object []> list = query.list();
382
383 if (list.isEmpty()) {
384 log.warn("River " + riverId + " has no fixings.");
385 // Its pretty fine to have no fixings.
386 }
387
388 for (Object [] row: list) {
389 int wstId = (Integer)row[0];
390 String description = (String) row[1];
391 Fixing fixing = new Fixing(wstId, description);
392 fixings.add(fixing);
393 }
394 }
395
396 protected void loadFixingsColumns(Session session) {
397 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS)
398 .addScalar("wst_column_id", StandardBasicTypes.INTEGER)
399 .addScalar("start_time", StandardBasicTypes.DATE)
400 .addScalar("name", StandardBasicTypes.STRING);
401
402 for (Fixing fixing: fixings) {
403 fixing.loadColumns(query);
404 }
405 }
406
407 protected void loadFixingsColumnsKmRange(Session session) {
408 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE)
409 .addScalar("start_km", StandardBasicTypes.DOUBLE)
410 .addScalar("stop_km", StandardBasicTypes.DOUBLE);
411
412 for (Fixing fixing: fixings) {
413 fixing.loadColumnsKmRange(query);
414 }
415 }
416
417 protected void loadFixingsColumnsQRanges(
418 Session session,
419 GaugeFinder gaugeFinder
420 ) {
421 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES)
422 .addScalar("q", StandardBasicTypes.DOUBLE)
423 .addScalar("start_km", StandardBasicTypes.DOUBLE)
424 .addScalar("stop_km", StandardBasicTypes.DOUBLE);
425
426 for (Fixing fixing: fixings) {
427 fixing.loadColumnsQRanges(query, gaugeFinder);
428 }
429 }
430
431 protected void adjustExtent() {
432 for (Fixing fixing: fixings) {
433 fixing.adjustExtent(extent);
434 }
435 }
436
437 public boolean load(Session session) {
438
439 if (!loadRiver(session)) {
440 return false;
441 }
442
443 GaugeFinderFactory gff = GaugeFinderFactory.getInstance();
444
445 GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp);
446
447 if (gaugeFinder == null) {
448 return false;
449 }
450
451 loadFixings(session);
452 loadFixingsColumns(session);
453 loadFixingsColumnsKmRange(session);
454
455 adjustExtent();
456
457 loadFixingsColumnsQRanges(session, gaugeFinder);
458
459 return true;
460 }
461
462 public static final Range FULL_EXTENT =
463 new Range(-Double.MAX_VALUE, Double.MAX_VALUE);
464
465 public static final Fixing.Filter ACCEPT = new Fixing.Filter() {
466 @Override
467 public boolean accept(Fixing.Column column) {
468 return true;
469 }
470 };
471
472 public static class NotFilter implements Fixing.Filter {
473 protected Fixing.Filter child;
474
475 public NotFilter(Fixing.Filter child) {
476 this.child = child;
477 }
478
479 @Override
480 public boolean accept(Fixing.Column column) {
481 return !child.accept(column);
482 }
483 } // class NotFilter
484
485 public static abstract class ComponentFilter implements Fixing.Filter {
486 protected List<Fixing.Filter> children;
487
488 public ComponentFilter() {
489 children = new ArrayList<Fixing.Filter>();
490 }
491
492 public ComponentFilter(List<Fixing.Filter> children) {
493 this.children = children;
494 }
495
496 public ComponentFilter add(Fixing.Filter filter) {
497 children.add(filter);
498 return this;
499 }
500 } // class ComponentFilter
501
502 public static class OrFilter extends ComponentFilter {
503
504 public OrFilter() {
505 }
506
507 public OrFilter(List<Fixing.Filter> children) {
508 super(children);
509 }
510
511 @Override
512 public boolean accept(Fixing.Column column) {
513 for (Fixing.Filter child: children) {
514 if (child.accept(column)) {
515 return true;
516 }
517 }
518 return false;
519 }
520 } // class OrFilter
521
522 public static class AndFilter extends ComponentFilter {
523
524 public AndFilter() {
525 }
526
527 public AndFilter(List<Fixing.Filter> children) {
528 super(children);
529 }
530
531 @Override
532 public boolean accept(Fixing.Column column) {
533 for (Fixing.Filter child: children) {
534 if (!child.accept(column)) {
535 return false;
536 }
537 }
538 return true;
539 }
540 } // class AndFilter
541
542 public static class IdFilter implements Fixing.Filter {
543
544 protected int columnId;
545
546 public IdFilter(int columnId) {
547 this.columnId = columnId;
548 }
549
550 @Override
551 public boolean accept(Fixing.Column column) {
552 return column.getId() == columnId;
553 }
554 } // class IdFilter
555
556 public static class IdsFilter implements Fixing.Filter {
557
558 protected int [] columnIds;
559
560 public IdsFilter(int [] columnIds) {
561 this.columnIds = columnIds;
562 }
563
564 @Override
565 public boolean accept(Fixing.Column column) {
566 int cid = column.getId();
567 for (int i = columnIds.length-1; i >= 0; --i) {
568 if (columnIds[i] == cid) {
569 return true;
570 }
571 }
572 return false;
573 }
574 } // class IdFilter
575
576 public static class DateFilter implements Fixing.Filter {
577
578 protected Date date;
579
580 public DateFilter(Date date) {
581 this.date = date;
582 }
583
584 @Override
585 public boolean accept(Fixing.Column column) {
586 return date.equals(column.getStartTime());
587 }
588 } // class DateFilter
589
590 public static class DateRangeFilter implements Fixing.Filter {
591
592 protected Date start;
593 protected Date end;
594
595 public DateRangeFilter(Date start, Date end) {
596 this.start = start;
597 this.end = end;
598 }
599
600 @Override
601 public boolean accept(Fixing.Column column) {
602 Date date = column.getStartTime();
603 return start.compareTo(date) <= 0 && end.compareTo(date) >= 0;
604 }
605 } // class DateRangeFilter
606
607 public static class SectorFilter implements Fixing.Filter {
608
609 protected int sector;
610
611 public SectorFilter(int sector) {
612 this.sector = sector;
613 }
614
615 @Override
616 public boolean accept(Fixing.Column column) {
617 for (SectorRange s: column.getSectors()) {
618 if (s.getSector() == sector) {
619 return true;
620 }
621 }
622 return false;
623 }
624 } // class SectorFilter
625
626 public static class SectorRangeFilter implements Fixing.Filter {
627
628 protected int min;
629 protected int max;
630
631 public SectorRangeFilter(int min, int max) {
632 this.min = Math.min(min, max);
633 this.max = Math.max(min, max);
634 }
635
636 @Override
637 public boolean accept(Fixing.Column column) {
638 for (SectorRange s: column.getSectors()) {
639 int v = s.getSector();
640 if (v >= min && v <= max) {
641 return true;
642 }
643 }
644 return false;
645 }
646 } // class SectorRangeFilter
647
648 public static class KmFilter implements Fixing.Filter {
649
650 protected double km;
651
652 public KmFilter(double km) {
653 this.km = km;
654 }
655
656 @Override
657 public boolean accept(Fixing.Column column) {
658 for (SectorRange s: column.getSectors()) {
659 if (s.inside(km)) {
660 return true;
661 }
662 }
663 return false;
664 }
665 } // class KmFilter
666
667 public void generateOverview(Document document) {
668 generateOverview(document, FULL_EXTENT, ACCEPT);
669 }
670
671 public List<Fixing.Column> filter(Range range, Fixing.Filter filter) {
672 List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>();
673
674 for (Fixing fixing: fixings) {
675 fixing.addAllColumns(allColumns, range, filter);
676 }
677
678 Collections.sort(allColumns, Fixing.DATE_CMP);
679
680 return allColumns;
681 }
682
683 public void generateOverview(
684 Document document,
685 Range range,
686 Fixing.Filter filter
687 ) {
688 List<Fixing.Column> allColumns = filter(range, filter);
689
690 Element fixingsElement = document.createElement("fixings");
691
692 Element riverElement = document.createElement("river");
693
694 riverElement.setAttribute("from", String.valueOf(extent.start));
695 riverElement.setAttribute("to", String.valueOf(extent.end));
696 riverElement.setAttribute("rid", String.valueOf(riverId));
697 riverElement.setAttribute("name", riverName);
698
699 fixingsElement.appendChild(riverElement);
700
701 SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
702
703 Element esE = document.createElement("events");
704
705 for (Fixing.Column column: allColumns) {
706
707 List<SectorRange> sectors = column.getSectors(range);
708
709 if (!sectors.isEmpty()) {
710 Element eE = document.createElement("event");
711 eE.setAttribute("description",
712 String.valueOf(column.getDescription()));
713 eE.setAttribute("cid", String.valueOf(column.columnId));
714 eE.setAttribute("date", df.format(column.startTime));
715
716 for (SectorRange sector: sectors) {
717 Element sE = document.createElement("sector");
718
719 sE.setAttribute("from", String.valueOf(sector.start));
720 sE.setAttribute("to", String.valueOf(sector.end));
721 sE.setAttribute("class", String.valueOf(sector.sector));
722
723 eE.appendChild(sE);
724 }
725
726 esE.appendChild(eE);
727 }
728 }
729
730 fixingsElement.appendChild(esE);
731
732 document.appendChild(fixingsElement);
733 }
734 }
735 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org