Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java @ 3651:06a65baae494
merged flys-artifacts/2.9
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:43 +0200 |
parents | 278b5508567e |
children | 658dc517fd7b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java Fri Sep 28 12:14:43 2012 +0200 @@ -0,0 +1,788 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.text.SimpleDateFormat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +import org.hibernate.type.StandardBasicTypes; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class FixingsOverview +implements Serializable +{ + private static Logger log = Logger.getLogger(FixingsOverview.class); + + public static final double EPSILON = 1e-2; + + public static final String DATE_FORMAT = "dd.MM.yyyy"; + + public static final String SQL_RIVER_ID = + "SELECT" + + " id AS river_id," + + " km_up " + + "FROM rivers " + + "WHERE" + + " name = :name"; + + public static final String SQL_FIXINGS = + "SELECT" + + " id AS wst_id," + + " description " + + "FROM wsts " + + "WHERE" + + " river_id = :river_id AND kind = 2"; + + public static final String SQL_FIXING_COLUMNS = + "SELECT" + + " wc.id AS wst_column_id," + + " ti.start_time AS start_time," + + " wc.name AS name " + + "FROM wst_columns wc" + + " JOIN time_intervals ti ON wc.time_interval_id = ti.id " + + "WHERE" + + " wc.wst_id = :wst_id " + + "ORDER BY position"; + + public static final String SQL_FIXING_COLUMN_Q_RANGES = + "SELECT" + + " wqr.q AS q," + + " r.a AS start_km," + + " r.b AS stop_km " + + "FROM wst_column_q_ranges wcqr" + + " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" + + " JOIN ranges r ON wqr.range_id = r.id " + + "WHERE" + + " wcqr.wst_column_id = :column_id " + + "ORDER BY r.a"; + + public static final String SQL_FIXING_COLUMN_KM_RANGE = + "SELECT" + + " MIN(position) AS start_km," + + " MAX(position) AS stop_km " + + "FROM" + + " wst_column_values " + + "WHERE" + + " wst_column_id = :column_id"; + + + public static class QRange extends Range { + + protected double q; + + public QRange() { + } + + public QRange(double start, double end, double q) { + super(start, end); + this.q = q; + } + } // class QRange + + public static class SectorRange extends Range { + + protected int sector; + + public SectorRange() { + } + + public SectorRange(SectorRange other) { + start = other.start; + end = other.end; + sector = other.sector; + } + + public SectorRange(Range range) { + super(range); + } + + public SectorRange(double start, double end, int sector) { + super(start, end); + this.sector = sector; + } + + public int getSector() { + return sector; + } + + public void setSector(int sector) { + this.sector = sector; + } + + public boolean enlarge(SectorRange other) { + if (sector == other.sector + && Math.abs(end-other.start) < FixingsOverview.EPSILON) { + end = other.end; + return true; + } + return false; + } + } // class SectorRange + + public static class Fixing implements Serializable { + + public static final Comparator<Column> DATE_CMP = + new Comparator<Column>() { + @Override + public int compare(Column a, Column b) { + return a.startTime.compareTo(b.startTime); + } + }; + + public interface Filter { + + boolean accept(Column column); + + } // interface Filter + + public class Column extends Range { + + protected int columnId; + protected Date startTime; + protected String name; + + protected List<SectorRange> sectors; + + public Column() { + } + + public Column(int columnId, Date startTime, String name) { + this.columnId = columnId; + this.startTime = startTime; + this.name = name; + + sectors = new ArrayList<SectorRange>(); + } + + public int getId() { + return columnId; + } + + public Fixing getFixing() { + return Fixing.this; + } + + public Date getStartTime() { + return startTime; + } + + public String getName() { + return name; + } + + public String getDescription() { + return Fixing.this.description + "/" + name; + } + + public List<SectorRange> getSectors() { + return sectors; + } + + public List<SectorRange> getSectors(Range range) { + + List<SectorRange> result = + new ArrayList<SectorRange>(sectors.size()); + + for (SectorRange src: sectors) { + SectorRange dst = new SectorRange(src); + if (range == null || dst.clip(range)) { + result.add(dst); + } + } + + return result; + } + + public int findQSector(double km) { + for (SectorRange sector: sectors) { + if (sector.inside(km)) { + return sector.getSector(); + } + } + return -1; + } + + public void buildSectors( + GaugeFinder gaugeFinder, + List<QRange> qRanges + ) { + for (QRange qRange: qRanges) { + for (GaugeRange gRange: gaugeFinder.getGauges()) { + SectorRange sector = new SectorRange(qRange); + if (!sector.clip(gRange)) { + continue; + } + sector.setSector(gRange.classify(qRange.q)); + + if (sectors.isEmpty() + || !sectors.get(sectors.size()-1).enlarge(sector)) { + sectors.add(sector); + } + } // for all gauges + } // for all Q ranges + } + + public void loadKmRange(SQLQuery query) { + query.setInteger("column_id", columnId); + + List<Object []> kms = query.list(); + + if (kms.isEmpty()) { + log.warn("No km range for column " + columnId + "."); + } + else { + Object [] obj = kms.get(0); + start = (Double)obj[0]; + end = (Double)obj[1]; + } + } + + public void loadQRanges( + SQLQuery query, + GaugeFinder gaugeFinder + ) { + query.setInteger("column_id", columnId); + List<Object []> list = query.list(); + + List<QRange> qRanges = new ArrayList<QRange>(list.size()); + + for (Object [] row: list) { + double q = (Double)row[0]; + double start = (Double)row[1]; + double end = (Double)row[2]; + QRange qRange = new QRange(start, end, q); + if (qRange.clip(this)) { + qRanges.add(qRange); + } + } + + buildSectors(gaugeFinder, qRanges); + } + } // class Column + + protected int wstId; + protected String description; + protected List<Column> columns; + + public Fixing() { + } + + public int getId() { + return wstId; + } + + public String getDescription() { + return description; + } + + public Fixing(int wstId, String description) { + this.wstId = wstId; + this.description = description; + columns = new ArrayList<Column>(); + } + + public void loadColumns(SQLQuery query) { + query.setInteger("wst_id", wstId); + List<Object []> list = query.list(); + for (Object [] row: list) { + int columnId = (Integer)row[0]; + Date startTime = (Date) row[1]; + String name = (String) row[2]; + columns.add(new Column(columnId, startTime, name)); + } + } + + public void loadColumnsKmRange(SQLQuery query) { + for (Column column: columns) { + column.loadKmRange(query); + } + } + + public void adjustExtent(Range extent) { + for (Column column: columns) { + extent.extend(column); + } + } + + public void loadColumnsQRanges( + SQLQuery query, + GaugeFinder gaugeFinder + ) { + for (Column column: columns) { + column.loadQRanges(query, gaugeFinder); + } + } + + public void addAllColumns( + List<Column> allColumns, + Range range, + Filter filter + ) { + for (Column column: columns) { + if ((range == null || column.intersects(range)) + && (filter == null || filter.accept(column))) { + allColumns.add(column); + } + } + } + } // class Fixing + + + protected String riverName; + protected int riverId; + protected boolean isKmUp; + protected List<Fixing> fixings; + protected Range extent; + + public FixingsOverview() { + fixings = new ArrayList<Fixing>(); + extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); + } + + public FixingsOverview(String riverName) { + this(); + this.riverName = riverName; + } + + protected boolean loadRiver(Session session) { + SQLQuery query = session.createSQLQuery(SQL_RIVER_ID) + .addScalar("river_id", StandardBasicTypes.INTEGER) + .addScalar("km_up", StandardBasicTypes.BOOLEAN); + + query.setString("name", riverName); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("No river '" + riverName + "' found."); + return false; + } + + Object [] row = list.get(0); + + riverId = (Integer)row[0]; + isKmUp = (Boolean)row[1]; + + return true; + } + + protected void loadFixings(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXINGS) + .addScalar("wst_id", StandardBasicTypes.INTEGER) + .addScalar("description", StandardBasicTypes.STRING); + + query.setInteger("river_id", riverId); + + List<Object []> list = query.list(); + + if (list.isEmpty()) { + log.warn("River " + riverId + " has no fixings."); + // Its pretty fine to have no fixings. + } + + for (Object [] row: list) { + int wstId = (Integer)row[0]; + String description = (String) row[1]; + Fixing fixing = new Fixing(wstId, description); + fixings.add(fixing); + } + } + + protected void loadFixingsColumns(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS) + .addScalar("wst_column_id", StandardBasicTypes.INTEGER) + .addScalar("start_time", StandardBasicTypes.DATE) + .addScalar("name", StandardBasicTypes.STRING); + + for (Fixing fixing: fixings) { + fixing.loadColumns(query); + } + } + + protected void loadFixingsColumnsKmRange(Session session) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + for (Fixing fixing: fixings) { + fixing.loadColumnsKmRange(query); + } + } + + protected void loadFixingsColumnsQRanges( + Session session, + GaugeFinder gaugeFinder + ) { + SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + for (Fixing fixing: fixings) { + fixing.loadColumnsQRanges(query, gaugeFinder); + } + } + + protected void adjustExtent() { + for (Fixing fixing: fixings) { + fixing.adjustExtent(extent); + } + } + + public boolean load(Session session) { + + if (!loadRiver(session)) { + return false; + } + + GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); + + GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp); + + if (gaugeFinder == null) { + return false; + } + + loadFixings(session); + loadFixingsColumns(session); + loadFixingsColumnsKmRange(session); + + adjustExtent(); + + loadFixingsColumnsQRanges(session, gaugeFinder); + + return true; + } + + public static final Range FULL_EXTENT = + new Range(-Double.MAX_VALUE, Double.MAX_VALUE); + + public static final Fixing.Filter ACCEPT = new Fixing.Filter() { + @Override + public boolean accept(Fixing.Column column) { + return true; + } + }; + + public static class NotFilter implements Fixing.Filter { + protected Fixing.Filter child; + + public NotFilter(Fixing.Filter child) { + this.child = child; + } + + @Override + public boolean accept(Fixing.Column column) { + return !child.accept(column); + } + } // class NotFilter + + public static abstract class ComponentFilter implements Fixing.Filter { + protected List<Fixing.Filter> children; + + public ComponentFilter() { + children = new ArrayList<Fixing.Filter>(); + } + + public ComponentFilter(List<Fixing.Filter> children) { + this.children = children; + } + + public ComponentFilter add(Fixing.Filter filter) { + children.add(filter); + return this; + } + } // class ComponentFilter + + public static class OrFilter extends ComponentFilter { + + public OrFilter() { + } + + public OrFilter(List<Fixing.Filter> children) { + super(children); + } + + @Override + public boolean accept(Fixing.Column column) { + for (Fixing.Filter child: children) { + if (child.accept(column)) { + return true; + } + } + return false; + } + } // class OrFilter + + public static class AndFilter extends ComponentFilter { + + public AndFilter() { + } + + public AndFilter(List<Fixing.Filter> children) { + super(children); + } + + @Override + public boolean accept(Fixing.Column column) { + for (Fixing.Filter child: children) { + if (!child.accept(column)) { + return false; + } + } + return true; + } + } // class AndFilter + + public static class IdFilter implements Fixing.Filter { + + protected int columnId; + + public IdFilter(int columnId) { + this.columnId = columnId; + } + + @Override + public boolean accept(Fixing.Column column) { + return column.getId() == columnId; + } + } // class IdFilter + + public static class IdsFilter implements Fixing.Filter { + + protected int [] columnIds; + + public IdsFilter(int [] columnIds) { + this.columnIds = columnIds; + } + + @Override + public boolean accept(Fixing.Column column) { + int cid = column.getId(); + for (int i = columnIds.length-1; i >= 0; --i) { + if (columnIds[i] == cid) { + return true; + } + } + return false; + } + } // class IdFilter + + public static class DateFilter implements Fixing.Filter { + + protected Date date; + + public DateFilter(Date date) { + this.date = date; + } + + @Override + public boolean accept(Fixing.Column column) { + return date.equals(column.getStartTime()); + } + } // class DateFilter + + public static class DateRangeFilter implements Fixing.Filter { + + protected Date start; + protected Date end; + + public DateRangeFilter(Date start, Date end) { + this.start = start; + this.end = end; + } + + @Override + public boolean accept(Fixing.Column column) { + Date date = column.getStartTime(); + return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; + } + } // class DateRangeFilter + + public static class SectorFilter implements Fixing.Filter { + + protected int sector; + + public SectorFilter(int sector) { + this.sector = sector; + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + if (s.getSector() == sector) { + return true; + } + } + return false; + } + } // class SectorFilter + + public static class SectorRangeFilter implements Fixing.Filter { + + protected int min; + protected int max; + + public SectorRangeFilter(int min, int max) { + this.min = Math.min(min, max); + this.max = Math.max(min, max); + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + int v = s.getSector(); + if (v >= min && v <= max) { + return true; + } + } + return false; + } + } // class SectorRangeFilter + + public static class KmFilter implements Fixing.Filter { + + protected double km; + + public KmFilter(double km) { + this.km = km; + } + + @Override + public boolean accept(Fixing.Column column) { + for (SectorRange s: column.getSectors()) { + if (s.inside(km)) { + return true; + } + } + return false; + } + } // class KmFilter + + public void generateOverview(Document document) { + generateOverview(document, FULL_EXTENT, ACCEPT); + } + + public List<Fixing.Column> filter(Range range, Fixing.Filter filter) { + List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); + + for (Fixing fixing: fixings) { + fixing.addAllColumns(allColumns, range, filter); + } + + Collections.sort(allColumns, Fixing.DATE_CMP); + + return allColumns; + } + + protected static Range realRange(List<Fixing.Column> columns) { + Range range = null; + for (Fixing.Column column: columns) { + if (range == null) { + range = new Range(column); + } + else { + range.extend(column); + } + } + return range; + } + + protected Element intersectingGauges(Document document, Range range) { + Element gauges = document.createElement("gauges"); + + if (range == null) { + return gauges; + } + + GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); + + GaugeFinder gf = gff.getGaugeFinder(riverId, isKmUp); + + if (gf == null) { + return gauges; + } + + for (GaugeRange gr: gf.getGauges()) { + if (gr.intersects(range)) { + Element gauge = document.createElement("gauge"); + gauge.setAttribute("from", String.valueOf(gr.getStart())); + gauge.setAttribute("to", String.valueOf(gr.getEnd())); + gauge.setAttribute("name", gr.getName()); + gauges.appendChild(gauge); + } + } + + return gauges; + } + + public void generateOverview( + Document document, + Range range, + Fixing.Filter filter + ) { + List<Fixing.Column> allColumns = filter(range, filter); + + Element fixingsElement = document.createElement("fixings"); + + Element riverElement = document.createElement("river"); + + riverElement.setAttribute("from", String.valueOf(extent.start)); + riverElement.setAttribute("to", String.valueOf(extent.end)); + riverElement.setAttribute("rid", String.valueOf(riverId)); + riverElement.setAttribute("name", riverName); + + fixingsElement.appendChild(riverElement); + + fixingsElement.appendChild( + intersectingGauges( + document, + realRange(allColumns))); + + SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); + + Element esE = document.createElement("events"); + + for (Fixing.Column column: allColumns) { + + List<SectorRange> sectors = column.getSectors(range); + + if (!sectors.isEmpty()) { + Element eE = document.createElement("event"); + eE.setAttribute("description", + String.valueOf(column.getDescription())); + eE.setAttribute("cid", String.valueOf(column.columnId)); + eE.setAttribute("date", df.format(column.startTime)); + + for (SectorRange sector: sectors) { + Element sE = document.createElement("sector"); + + sE.setAttribute("from", String.valueOf(sector.start)); + sE.setAttribute("to", String.valueOf(sector.end)); + sE.setAttribute("class", String.valueOf(sector.sector)); + + eE.appendChild(sE); + } + + esE.appendChild(eE); + } + } + + fixingsElement.appendChild(esE); + + document.appendChild(fixingsElement); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :