teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.artifacts.model; sascha@2561: sascha@2561: import java.io.Serializable; sascha@2561: sascha@2561: import java.text.SimpleDateFormat; sascha@2561: sascha@2561: import java.util.ArrayList; sascha@2561: import java.util.Collections; sascha@2561: import java.util.Comparator; sascha@2561: import java.util.Date; sascha@2561: import java.util.List; sascha@2561: sascha@2561: import org.apache.log4j.Logger; sascha@2561: sascha@2561: import org.hibernate.SQLQuery; sascha@2561: import org.hibernate.Session; sascha@2561: sascha@2561: import org.hibernate.type.StandardBasicTypes; sascha@2561: sascha@2561: import org.w3c.dom.Document; sascha@2561: import org.w3c.dom.Element; sascha@2561: teichmann@6847: import org.dive4elements.river.utils.BatchLoader; felix@5343: teichmann@6847: teichmann@6847: /** Generate Fixings Table overview data structure to be stored in cache. */ sascha@2561: public class FixingsOverview sascha@2561: implements Serializable sascha@2561: { sascha@2561: private static Logger log = Logger.getLogger(FixingsOverview.class); sascha@2561: sascha@3430: public static final double EPSILON = 1e-2; sascha@2561: sascha@2632: public static final String DATE_FORMAT = "dd.MM.yyyy"; sascha@2564: sascha@2561: public static final String SQL_RIVER_ID = sascha@2561: "SELECT" + sascha@2561: " id AS river_id," + sascha@2561: " km_up " + sascha@2561: "FROM rivers " + sascha@2561: "WHERE" + sascha@2561: " name = :name"; sascha@2561: felix@5725: /** All kind-2 wsts from given river. */ sascha@2561: public static final String SQL_FIXINGS = sascha@2561: "SELECT" + sascha@2561: " id AS wst_id," + sascha@2561: " description " + sascha@2561: "FROM wsts " + sascha@2561: "WHERE" + sascha@2561: " river_id = :river_id AND kind = 2"; sascha@2561: teichmann@6847: public static final String SQL_FIXING_COLUMNS_BATCH = teichmann@6847: "SELECT " + teichmann@6847: "wc.wst_id AS wst_id," + teichmann@6847: "wc.id AS wst_column_id," + teichmann@6847: "ti.start_time AS start_time," + teichmann@6847: "wc.name AS name " + teichmann@6847: "FROM wst_columns wc " + teichmann@6847: "JOIN time_intervals ti ON wc.time_interval_id = ti.id " + teichmann@6847: "WHERE " + teichmann@6847: "wc.wst_id IN ($IDS) " + teichmann@6847: "ORDER BY wc.wst_id, position"; sascha@2561: teichmann@6847: public static final String SQL_FIXING_COLUMN_Q_RANGES_BATCH = teichmann@6847: "SELECT " + teichmann@6847: "wcqr.wst_column_id AS wst_column_id," + teichmann@6847: "wqr.q AS q," + teichmann@6847: "r.a AS start_km," + teichmann@6847: "r.b AS stop_km " + teichmann@6847: "FROM wst_column_q_ranges wcqr " + teichmann@6847: "JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id " + teichmann@6847: "JOIN ranges r ON wqr.range_id = r.id " + teichmann@6847: "WHERE " + teichmann@6847: "wcqr.wst_column_id IN ($IDS) " + teichmann@6847: "ORDER BY wcqr.wst_column_id, r.a"; sascha@2561: teichmann@6847: public static final String SQL_FIXING_COLUMN_KM_RANGE_BATCH = teichmann@6847: "SELECT " + teichmann@6847: "wst_column_id," + teichmann@6847: "MIN(position) AS start_km," + teichmann@6847: "MAX(position) AS stop_km " + teichmann@6847: "FROM " + teichmann@6847: "wst_column_values " + teichmann@6847: "WHERE " + teichmann@6847: "wst_column_id IN ($IDS) " + teichmann@6847: "GROUP BY wst_column_id"; sascha@2561: teichmann@6847: public static final class KMRangeLoader extends BatchLoader { teichmann@6847: teichmann@6847: public KMRangeLoader(List columns, Session session) { teichmann@6847: super(columns, session, SQL_FIXING_COLUMN_KM_RANGE_BATCH); teichmann@6847: } teichmann@6847: teichmann@6847: @Override teichmann@6847: protected void fill(SQLQuery query) { teichmann@6847: query teichmann@6847: .addScalar("wst_column_id", StandardBasicTypes.INTEGER) teichmann@6847: .addScalar("start_km", StandardBasicTypes.DOUBLE) teichmann@6847: .addScalar("stop_km", StandardBasicTypes.DOUBLE); teichmann@6847: teichmann@6847: List ranges = query.list(); teichmann@6847: for (Object [] r: ranges) { teichmann@6847: Integer cid = (Integer)r[0]; teichmann@6847: double [] vs = new double [] { (Double)r[1], (Double)r[2] }; teichmann@6847: cache(cid, vs); teichmann@6847: } teichmann@6847: } teichmann@6847: } // class KMRangeLoader teichmann@6847: teichmann@6847: public static final class ColumnQRangeLoader extends BatchLoader> { teichmann@6847: teichmann@6847: public ColumnQRangeLoader(List columns, Session session) { teichmann@6847: super(columns, session, SQL_FIXING_COLUMN_Q_RANGES_BATCH); teichmann@6847: } teichmann@6847: teichmann@6847: @Override teichmann@6847: protected void fill(SQLQuery query) { teichmann@6847: query teichmann@6847: .addScalar("wst_column_id", StandardBasicTypes.INTEGER) teichmann@6847: .addScalar("q", StandardBasicTypes.DOUBLE) teichmann@6847: .addScalar("start_km", StandardBasicTypes.DOUBLE) teichmann@6847: .addScalar("stop_km", StandardBasicTypes.DOUBLE); teichmann@6847: teichmann@6847: int lastId = Integer.MIN_VALUE; teichmann@6847: List column = new ArrayList(); teichmann@6847: teichmann@6847: List ranges = query.list(); teichmann@6847: for (Object [] r: ranges) { teichmann@6847: int cid = (Integer)r[0]; teichmann@6847: teichmann@6847: if (cid != lastId && !column.isEmpty()) { teichmann@6847: cache(lastId, column); teichmann@6847: column = new ArrayList(); teichmann@6847: } teichmann@6847: column.add(new double [] { teichmann@6847: (Double)r[1], teichmann@6847: (Double)r[2], teichmann@6847: (Double)r[3] teichmann@6847: }); teichmann@6847: teichmann@6847: lastId = cid; teichmann@6847: } teichmann@6847: teichmann@6847: if (!column.isEmpty()) { teichmann@6847: cache(lastId, column); teichmann@6847: } teichmann@6847: } teichmann@6847: } // class ColumnQRangeLoader teichmann@6847: teichmann@6847: /** Helper class to store data from batching fixing columns. */ teichmann@6847: private static final class FixColumn { teichmann@6847: int columnId; teichmann@6847: Date startTime; teichmann@6847: String name; teichmann@6847: teichmann@6847: FixColumn(int columnId, Date startTime, String name) { teichmann@6847: this.columnId = columnId; teichmann@6847: this.startTime = startTime; teichmann@6847: this.name = name; teichmann@6847: } teichmann@6847: } // class FixColumn teichmann@6847: teichmann@6847: public static final class FixColumnLoader extends BatchLoader> { teichmann@6847: teichmann@6847: public FixColumnLoader(List columns, Session session) { teichmann@6847: super(columns, session, SQL_FIXING_COLUMNS_BATCH); teichmann@6847: } teichmann@6847: teichmann@6847: @Override teichmann@6847: protected void fill(SQLQuery query) { teichmann@6847: query teichmann@6847: .addScalar("wst_id", StandardBasicTypes.INTEGER) teichmann@6847: .addScalar("wst_column_id", StandardBasicTypes.INTEGER) teichmann@6847: .addScalar("start_time", StandardBasicTypes.DATE) teichmann@6847: .addScalar("name", StandardBasicTypes.STRING); teichmann@6847: teichmann@6847: int lastId = Integer.MIN_VALUE; teichmann@6847: List cols = new ArrayList(); teichmann@6847: teichmann@6847: List columns = query.list(); teichmann@6847: for (Object [] c: columns) { teichmann@6847: int wid = (Integer)c[0]; teichmann@6847: teichmann@6847: if (wid != lastId && !cols.isEmpty()) { teichmann@6847: cache(lastId, cols); teichmann@6847: cols = new ArrayList(); teichmann@6847: } teichmann@6847: cols.add(new FixColumn( teichmann@6847: (Integer)c[1], teichmann@6847: (Date) c[2], teichmann@6847: (String) c[3])); teichmann@6847: teichmann@6847: lastId = wid; teichmann@6847: } teichmann@6847: if (!cols.isEmpty()) { teichmann@6847: cache(lastId, cols); teichmann@6847: } teichmann@6847: } teichmann@6847: } // class FixColumnLoader sascha@2561: sascha@2561: public static class QRange extends Range { sascha@2561: sascha@2561: protected double q; sascha@2561: sascha@2561: public QRange() { sascha@2561: } sascha@2561: sascha@2561: public QRange(double start, double end, double q) { sascha@2561: super(start, end); sascha@2561: this.q = q; sascha@2561: } sascha@2561: } // class QRange sascha@2561: sascha@2561: public static class SectorRange extends Range { sascha@2561: sascha@2561: protected int sector; sascha@2561: sascha@2561: public SectorRange() { sascha@2561: } sascha@2561: sascha@2562: public SectorRange(SectorRange other) { sascha@2562: start = other.start; sascha@2562: end = other.end; sascha@2562: sector = other.sector; sascha@2562: } sascha@2562: sascha@3401: public SectorRange(Range range) { sascha@3401: super(range); sascha@3401: } sascha@3401: sascha@2561: public SectorRange(double start, double end, int sector) { sascha@2561: super(start, end); sascha@2561: this.sector = sector; sascha@2561: } sascha@2561: sascha@2562: public int getSector() { sascha@2562: return sector; sascha@2562: } sascha@2562: sascha@3401: public void setSector(int sector) { sascha@3401: this.sector = sector; sascha@3401: } sascha@3401: sascha@2561: public boolean enlarge(SectorRange other) { sascha@2561: if (sector == other.sector sascha@3430: && Math.abs(end-other.start) < FixingsOverview.EPSILON) { sascha@2561: end = other.end; sascha@2561: return true; sascha@2561: } sascha@2561: return false; sascha@2561: } sascha@2561: } // class SectorRange sascha@2561: sascha@2561: public static class Fixing implements Serializable { sascha@2561: sascha@2561: public static final Comparator DATE_CMP = sascha@2561: new Comparator() { sascha@2561: @Override sascha@2561: public int compare(Column a, Column b) { sascha@2561: return a.startTime.compareTo(b.startTime); sascha@2561: } sascha@2561: }; sascha@2561: sascha@2563: public interface Filter { sascha@2563: sascha@2563: boolean accept(Column column); sascha@2563: sascha@2563: } // interface Filter sascha@2563: sascha@2561: public class Column extends Range { sascha@2561: sascha@2561: protected int columnId; sascha@2561: protected Date startTime; sascha@2561: protected String name; sascha@2561: sascha@2562: protected List sectors; sascha@2561: sascha@2561: public Column() { sascha@2561: } sascha@2561: sascha@2561: public Column(int columnId, Date startTime, String name) { sascha@2561: this.columnId = columnId; sascha@2561: this.startTime = startTime; sascha@2561: this.name = name; sascha@3076: sascha@2562: sectors = new ArrayList(); sascha@2561: } sascha@2561: sascha@2563: public int getId() { sascha@2563: return columnId; sascha@2563: } sascha@2563: sascha@2561: public Fixing getFixing() { sascha@2561: return Fixing.this; sascha@2561: } sascha@2561: sascha@2563: public Date getStartTime() { sascha@2563: return startTime; sascha@2563: } sascha@2563: sascha@2563: public String getName() { sascha@2563: return name; sascha@2563: } sascha@2563: sascha@2707: public String getDescription() { sascha@2707: return Fixing.this.description + "/" + name; sascha@2707: } sascha@2707: sascha@2562: public List getSectors() { sascha@2562: return sectors; sascha@2562: } sascha@2561: teichmann@5804: public boolean hasSectorsInRange(Range range) { teichmann@5804: for (SectorRange sector: sectors) { teichmann@5804: if (sector.intersects(range)) { teichmann@5804: return true; teichmann@5804: } teichmann@5804: } teichmann@5804: return false; teichmann@5804: } teichmann@5804: sascha@2563: public List getSectors(Range range) { sascha@2563: sascha@2563: List result = sascha@2563: new ArrayList(sectors.size()); sascha@2563: sascha@2563: for (SectorRange src: sectors) { sascha@2563: SectorRange dst = new SectorRange(src); sascha@2613: if (range == null || dst.clip(range)) { sascha@2563: result.add(dst); sascha@2563: } sascha@2563: } sascha@2563: sascha@2563: return result; sascha@2563: } sascha@2563: sascha@3002: public int findQSector(double km) { sascha@3002: for (SectorRange sector: sectors) { sascha@3002: if (sector.inside(km)) { sascha@3002: return sector.getSector(); sascha@3002: } sascha@3002: } sascha@3002: return -1; sascha@3002: } sascha@3002: sascha@3401: public void buildSectors( sascha@3401: GaugeFinder gaugeFinder, sascha@3401: List qRanges sascha@3401: ) { sascha@2561: for (QRange qRange: qRanges) { sascha@3401: for (GaugeRange gRange: gaugeFinder.getGauges()) { sascha@3401: SectorRange sector = new SectorRange(qRange); sascha@3401: if (!sector.clip(gRange)) { sascha@3401: continue; sascha@3401: } sascha@3401: sector.setSector(gRange.classify(qRange.q)); sascha@3401: sascha@3401: if (sectors.isEmpty() sascha@3401: || !sectors.get(sectors.size()-1).enlarge(sector)) { sascha@3401: sectors.add(sector); sascha@3401: } sascha@3401: } // for all gauges sascha@3401: } // for all Q ranges sascha@2561: } sascha@2561: teichmann@6847: public void loadKmRange(KMRangeLoader loader) { sascha@2561: teichmann@6847: double [] range = loader.get(columnId); teichmann@6847: teichmann@6847: if (range == null) { sascha@2561: log.warn("No km range for column " + columnId + "."); teichmann@6847: return; sascha@2561: } teichmann@6847: start = range[0]; teichmann@6847: end = range[1]; sascha@2561: } sascha@2561: sascha@2562: public void loadQRanges( teichmann@6847: ColumnQRangeLoader loader, teichmann@6847: GaugeFinder gaugeFinder sascha@2562: ) { teichmann@6847: List qrs = loader.get(columnId); teichmann@6847: if (qrs == null) { teichmann@6847: log.warn("No q ranges found for column " + columnId); teichmann@6847: return; teichmann@6847: } sascha@2561: teichmann@6847: List qRanges = new ArrayList(qrs.size()); sascha@2562: teichmann@6847: for (double [] qr: qrs) { teichmann@6847: double q = qr[0]; teichmann@6847: double start = qr[1]; teichmann@6847: double end = qr[2]; teichmann@6847: sascha@2561: QRange qRange = new QRange(start, end, q); sascha@2561: if (qRange.clip(this)) { sascha@2561: qRanges.add(qRange); sascha@2561: } sascha@2561: } sascha@2562: sascha@3401: buildSectors(gaugeFinder, qRanges); sascha@2561: } sascha@2561: } // class Column sascha@2561: sascha@2562: protected int wstId; sascha@2562: protected String description; sascha@2561: protected List columns; sascha@2561: sascha@2561: public Fixing() { sascha@2561: } sascha@2561: sascha@2563: public int getId() { sascha@2563: return wstId; sascha@2563: } sascha@2563: sascha@2563: public String getDescription() { sascha@2563: return description; sascha@2563: } sascha@2563: sascha@2561: public Fixing(int wstId, String description) { sascha@2561: this.wstId = wstId; sascha@2561: this.description = description; sascha@2561: columns = new ArrayList(); sascha@2561: } sascha@2561: teichmann@6847: public void allColumnIds(List cIds) { teichmann@6847: for (Column column: columns) { teichmann@6847: cIds.add(column.columnId); sascha@2561: } sascha@2561: } sascha@2561: teichmann@6847: public void loadColumns(FixColumnLoader loader) { teichmann@6847: List fcs = loader.get(wstId); teichmann@6847: if (fcs == null) { teichmann@6847: log.warn("No columns for wst " + wstId); teichmann@6847: return; teichmann@6847: } teichmann@6847: for (FixColumn fc: fcs) { teichmann@6847: columns.add(new Column(fc.columnId, fc.startTime, fc.name)); teichmann@6847: } teichmann@6847: } teichmann@6847: teichmann@6847: public void loadColumnsKmRange(KMRangeLoader loader) { sascha@2561: for (Column column: columns) { teichmann@6847: column.loadKmRange(loader); sascha@2561: } sascha@2561: } sascha@2561: sascha@2565: public void adjustExtent(Range extent) { sascha@2565: for (Column column: columns) { sascha@2565: extent.extend(column); sascha@2565: } sascha@2565: } sascha@2565: sascha@2562: public void loadColumnsQRanges( teichmann@6847: ColumnQRangeLoader loader, teichmann@6847: GaugeFinder gaugeFinder sascha@2562: ) { sascha@2561: for (Column column: columns) { teichmann@6847: column.loadQRanges(loader, gaugeFinder); sascha@2561: } sascha@2561: } sascha@2561: felix@5725: /** felix@5725: * @param allColumns[out] Columns will be put here. felix@5725: * @param range can be null. felix@5725: * @param filter filter to apply. felix@5725: */ sascha@2563: public void addAllColumns( sascha@2563: List allColumns, sascha@2563: Range range, sascha@2563: Filter filter sascha@2563: ) { sascha@2562: for (Column column: columns) { teichmann@5804: if ((range == null || column.hasSectorsInRange(range)) sascha@3076: && (filter == null || filter.accept(column))) { sascha@2562: allColumns.add(column); sascha@2562: } sascha@2562: } sascha@2561: } sascha@2561: } // class Fixing sascha@2561: sascha@2561: sascha@2562: protected String riverName; sascha@2562: protected int riverId; sascha@2562: protected boolean isKmUp; sascha@2562: protected List fixings; sascha@2562: protected Range extent; sascha@2561: sascha@2561: public FixingsOverview() { sascha@2561: fixings = new ArrayList(); sascha@2565: extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); sascha@2561: } sascha@2561: sascha@2561: public FixingsOverview(String riverName) { sascha@2561: this(); sascha@2561: this.riverName = riverName; sascha@2561: } sascha@2561: sascha@2561: protected boolean loadRiver(Session session) { sascha@2561: SQLQuery query = session.createSQLQuery(SQL_RIVER_ID) sascha@2561: .addScalar("river_id", StandardBasicTypes.INTEGER) sascha@2561: .addScalar("km_up", StandardBasicTypes.BOOLEAN); sascha@2561: sascha@2561: query.setString("name", riverName); sascha@2561: sascha@2561: List list = query.list(); sascha@2561: sascha@2561: if (list.isEmpty()) { sascha@2561: log.warn("No river '" + riverName + "' found."); sascha@2561: return false; sascha@2561: } sascha@2561: sascha@2561: Object [] row = list.get(0); sascha@2561: sascha@2561: riverId = (Integer)row[0]; sascha@2561: isKmUp = (Boolean)row[1]; sascha@2561: sascha@2561: return true; sascha@2561: } sascha@2561: sascha@2561: protected void loadFixings(Session session) { sascha@2561: SQLQuery query = session.createSQLQuery(SQL_FIXINGS) sascha@2561: .addScalar("wst_id", StandardBasicTypes.INTEGER) sascha@2561: .addScalar("description", StandardBasicTypes.STRING); sascha@2561: sascha@2561: query.setInteger("river_id", riverId); sascha@2561: sascha@2561: List list = query.list(); sascha@2561: sascha@2561: if (list.isEmpty()) { sascha@2561: log.warn("River " + riverId + " has no fixings."); sascha@2561: // Its pretty fine to have no fixings. sascha@2561: } sascha@2561: sascha@2561: for (Object [] row: list) { sascha@2561: int wstId = (Integer)row[0]; sascha@2561: String description = (String) row[1]; sascha@2561: Fixing fixing = new Fixing(wstId, description); sascha@2561: fixings.add(fixing); sascha@2561: } sascha@2561: } sascha@2561: sascha@2561: protected void loadFixingsColumns(Session session) { teichmann@6847: teichmann@6847: FixColumnLoader loader = new FixColumnLoader( teichmann@6847: allFixingIds(), teichmann@6847: session); sascha@2561: sascha@2561: for (Fixing fixing: fixings) { teichmann@6847: fixing.loadColumns(loader); sascha@2561: } sascha@2561: } sascha@2561: teichmann@6847: protected List allFixingIds() { teichmann@6847: List ids = new ArrayList(fixings.size()); teichmann@6847: for (Fixing fixing: fixings) { teichmann@6847: ids.add(fixing.getId()); teichmann@6847: } teichmann@6847: return ids; teichmann@6847: } teichmann@6847: teichmann@6847: protected List allColumnIds() { teichmann@6847: List cIds = new ArrayList(); teichmann@6847: for (Fixing fixing: fixings) { teichmann@6847: fixing.allColumnIds(cIds); teichmann@6847: } teichmann@6847: return cIds; teichmann@6847: } teichmann@6847: sascha@2561: protected void loadFixingsColumnsKmRange(Session session) { teichmann@6847: teichmann@6847: KMRangeLoader loader = new KMRangeLoader( teichmann@6847: allColumnIds(), teichmann@6847: session); sascha@2561: sascha@2561: for (Fixing fixing: fixings) { teichmann@6847: fixing.loadColumnsKmRange(loader); sascha@2561: } sascha@2561: } sascha@2561: sascha@2562: protected void loadFixingsColumnsQRanges( sascha@2562: Session session, sascha@2562: GaugeFinder gaugeFinder sascha@2562: ) { teichmann@6847: teichmann@6847: ColumnQRangeLoader loader = new ColumnQRangeLoader( teichmann@6847: allColumnIds(), teichmann@6847: session); sascha@2561: sascha@2561: for (Fixing fixing: fixings) { teichmann@6847: fixing.loadColumnsQRanges(loader, gaugeFinder); sascha@2561: } sascha@2561: } sascha@2561: sascha@2565: protected void adjustExtent() { sascha@2565: for (Fixing fixing: fixings) { sascha@2565: fixing.adjustExtent(extent); sascha@2565: } sascha@2565: } sascha@2565: sascha@2561: public boolean load(Session session) { sascha@2561: sascha@2565: if (!loadRiver(session)) { sascha@2561: return false; sascha@2561: } sascha@2561: sascha@3143: GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); sascha@2561: sascha@3143: GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp); sascha@3143: sascha@3143: if (gaugeFinder == null) { sascha@2561: return false; sascha@2561: } sascha@2561: sascha@2561: loadFixings(session); sascha@2561: loadFixingsColumns(session); sascha@2561: loadFixingsColumnsKmRange(session); sascha@2565: sascha@2565: adjustExtent(); sascha@2565: sascha@2562: loadFixingsColumnsQRanges(session, gaugeFinder); sascha@2561: sascha@2561: return true; sascha@2561: } sascha@2561: sascha@2563: public static final Range FULL_EXTENT = sascha@2562: new Range(-Double.MAX_VALUE, Double.MAX_VALUE); sascha@2562: sascha@2563: public static final Fixing.Filter ACCEPT = new Fixing.Filter() { sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: return true; sascha@2563: } sascha@2563: }; sascha@2563: sascha@2563: public static class NotFilter implements Fixing.Filter { sascha@2563: protected Fixing.Filter child; sascha@2563: sascha@2563: public NotFilter(Fixing.Filter child) { sascha@2563: this.child = child; sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: return !child.accept(column); sascha@2563: } sascha@2563: } // class NotFilter sascha@2563: sascha@2563: public static abstract class ComponentFilter implements Fixing.Filter { sascha@2563: protected List children; sascha@2563: sascha@2744: public ComponentFilter() { sascha@2744: children = new ArrayList(); sascha@2744: } sascha@2744: sascha@2563: public ComponentFilter(List children) { sascha@2563: this.children = children; sascha@2563: } sascha@2744: sascha@3121: public ComponentFilter add(Fixing.Filter filter) { sascha@2744: children.add(filter); sascha@3121: return this; sascha@2744: } sascha@2563: } // class ComponentFilter sascha@2563: sascha@2563: public static class OrFilter extends ComponentFilter { sascha@2563: sascha@2744: public OrFilter() { sascha@2744: } sascha@2744: sascha@2563: public OrFilter(List children) { sascha@2563: super(children); sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: for (Fixing.Filter child: children) { sascha@2563: if (child.accept(column)) { sascha@2563: return true; sascha@2563: } sascha@2563: } sascha@2563: return false; sascha@2563: } sascha@2563: } // class OrFilter sascha@2563: sascha@2563: public static class AndFilter extends ComponentFilter { sascha@2563: sascha@2744: public AndFilter() { sascha@2744: } sascha@2744: sascha@2563: public AndFilter(List children) { sascha@2563: super(children); sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: for (Fixing.Filter child: children) { sascha@2563: if (!child.accept(column)) { sascha@2563: return false; sascha@2563: } sascha@2563: } sascha@2563: return true; sascha@2563: } sascha@2563: } // class AndFilter sascha@2563: sascha@2563: public static class IdFilter implements Fixing.Filter { sascha@2563: sascha@2563: protected int columnId; sascha@2563: sascha@2563: public IdFilter(int columnId) { sascha@2563: this.columnId = columnId; sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: return column.getId() == columnId; sascha@2563: } sascha@2563: } // class IdFilter sascha@2563: felix@5725: /** Accept Fixing columns whose id is in id list. */ sascha@3121: public static class IdsFilter implements Fixing.Filter { sascha@3121: sascha@3121: protected int [] columnIds; sascha@3121: sascha@3121: public IdsFilter(int [] columnIds) { sascha@3121: this.columnIds = columnIds; sascha@3121: } sascha@3121: sascha@3121: @Override sascha@3121: public boolean accept(Fixing.Column column) { sascha@3121: int cid = column.getId(); sascha@3121: for (int i = columnIds.length-1; i >= 0; --i) { sascha@3121: if (columnIds[i] == cid) { sascha@3121: return true; sascha@3121: } sascha@3121: } sascha@3121: return false; sascha@3121: } sascha@3121: } // class IdFilter sascha@3121: sascha@2563: public static class DateFilter implements Fixing.Filter { sascha@2563: sascha@2563: protected Date date; sascha@2563: sascha@2563: public DateFilter(Date date) { sascha@2563: this.date = date; sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: return date.equals(column.getStartTime()); sascha@2563: } sascha@2563: } // class DateFilter sascha@2563: sascha@2563: public static class DateRangeFilter implements Fixing.Filter { sascha@2563: sascha@2563: protected Date start; sascha@2563: protected Date end; sascha@2563: sascha@2563: public DateRangeFilter(Date start, Date end) { sascha@2563: this.start = start; sascha@2563: this.end = end; sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: Date date = column.getStartTime(); sascha@2563: return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; sascha@2563: } sascha@2563: } // class DateRangeFilter sascha@2563: sascha@3008: public static class SectorFilter implements Fixing.Filter { sascha@3008: sascha@3008: protected int sector; sascha@3008: sascha@3008: public SectorFilter(int sector) { sascha@3008: this.sector = sector; sascha@3008: } sascha@3008: sascha@3008: @Override sascha@3008: public boolean accept(Fixing.Column column) { sascha@3008: for (SectorRange s: column.getSectors()) { sascha@3008: if (s.getSector() == sector) { sascha@3008: return true; sascha@3008: } sascha@3008: } sascha@3008: return false; sascha@3008: } sascha@3008: } // class SectorFilter sascha@3008: sascha@2563: public static class SectorRangeFilter implements Fixing.Filter { sascha@2563: sascha@2563: protected int min; sascha@2563: protected int max; sascha@2563: sascha@2563: public SectorRangeFilter(int min, int max) { sascha@2563: this.min = Math.min(min, max); sascha@2563: this.max = Math.max(min, max); sascha@2563: } sascha@2563: sascha@2563: @Override sascha@2563: public boolean accept(Fixing.Column column) { sascha@2563: for (SectorRange s: column.getSectors()) { sascha@2563: int v = s.getSector(); felix@5153: if (v < min || v > max) { felix@5153: return false; sascha@2563: } sascha@2563: } felix@5153: return true; sascha@2563: } sascha@2563: } // class SectorRangeFilter sascha@2563: sascha@3006: public static class KmFilter implements Fixing.Filter { sascha@3006: sascha@3006: protected double km; sascha@3006: sascha@3006: public KmFilter(double km) { sascha@3006: this.km = km; sascha@3006: } sascha@3006: sascha@3006: @Override sascha@3006: public boolean accept(Fixing.Column column) { sascha@3006: for (SectorRange s: column.getSectors()) { sascha@3006: if (s.inside(km)) { sascha@3006: return true; sascha@3006: } sascha@3006: } sascha@3006: return false; sascha@3006: } sascha@3006: } // class KmFilter sascha@3006: sascha@2561: public void generateOverview(Document document) { sascha@2563: generateOverview(document, FULL_EXTENT, ACCEPT); sascha@2562: } sascha@2562: felix@5996: /** felix@5996: * @param range can be null. felix@5996: */ sascha@2608: public List filter(Range range, Fixing.Filter filter) { sascha@2561: List allColumns = new ArrayList(); sascha@2561: sascha@2561: for (Fixing fixing: fixings) { sascha@2563: fixing.addAllColumns(allColumns, range, filter); sascha@2561: } sascha@2561: sascha@2561: Collections.sort(allColumns, Fixing.DATE_CMP); sascha@2561: sascha@2608: return allColumns; sascha@2608: } sascha@2608: sascha@3421: protected static Range realRange(List columns) { sascha@3421: Range range = null; sascha@3421: for (Fixing.Column column: columns) { sascha@3421: if (range == null) { sascha@3421: range = new Range(column); sascha@3421: } sascha@3421: else { sascha@3421: range.extend(column); sascha@3421: } sascha@3421: } sascha@3421: return range; sascha@3421: } sascha@3421: sascha@3421: protected Element intersectingGauges(Document document, Range range) { sascha@3421: Element gauges = document.createElement("gauges"); sascha@3421: sascha@3421: if (range == null) { sascha@3421: return gauges; sascha@3421: } sascha@3421: sascha@3421: GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); sascha@3421: sascha@3421: GaugeFinder gf = gff.getGaugeFinder(riverId, isKmUp); sascha@3421: sascha@3421: if (gf == null) { sascha@3421: return gauges; sascha@3421: } sascha@3421: sascha@3421: for (GaugeRange gr: gf.getGauges()) { sascha@3421: if (gr.intersects(range)) { sascha@3421: Element gauge = document.createElement("gauge"); sascha@3421: gauge.setAttribute("from", String.valueOf(gr.getStart())); sascha@3421: gauge.setAttribute("to", String.valueOf(gr.getEnd())); sascha@3421: gauge.setAttribute("name", gr.getName()); sascha@3421: gauges.appendChild(gauge); sascha@3421: } sascha@3421: } sascha@3421: sascha@3421: return gauges; sascha@3421: } sascha@3421: felix@5335: /** Populate document with fixings, filtered by range and filter. */ sascha@2608: public void generateOverview( sascha@2608: Document document, sascha@2608: Range range, sascha@2608: Fixing.Filter filter sascha@2608: ) { sascha@2608: List allColumns = filter(range, filter); sascha@2608: sascha@2561: Element fixingsElement = document.createElement("fixings"); sascha@2561: sascha@2561: Element riverElement = document.createElement("river"); sascha@2561: sascha@2561: riverElement.setAttribute("from", String.valueOf(extent.start)); sascha@2561: riverElement.setAttribute("to", String.valueOf(extent.end)); sascha@2561: riverElement.setAttribute("rid", String.valueOf(riverId)); sascha@2565: riverElement.setAttribute("name", riverName); sascha@2561: sascha@2561: fixingsElement.appendChild(riverElement); sascha@2561: sascha@3421: fixingsElement.appendChild( sascha@3421: intersectingGauges( sascha@3421: document, sascha@3421: realRange(allColumns))); sascha@3421: sascha@2564: SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); sascha@2561: sascha@2561: Element esE = document.createElement("events"); sascha@2561: sascha@2561: for (Fixing.Column column: allColumns) { sascha@2561: sascha@2563: List sectors = column.getSectors(range); sascha@2561: sascha@2561: if (!sectors.isEmpty()) { sascha@2561: Element eE = document.createElement("event"); sascha@2707: eE.setAttribute("description", sascha@2707: String.valueOf(column.getDescription())); sascha@2561: eE.setAttribute("cid", String.valueOf(column.columnId)); sascha@2561: eE.setAttribute("date", df.format(column.startTime)); sascha@2561: sascha@2561: for (SectorRange sector: sectors) { sascha@2561: Element sE = document.createElement("sector"); sascha@2561: sascha@2561: sE.setAttribute("from", String.valueOf(sector.start)); sascha@2561: sE.setAttribute("to", String.valueOf(sector.end)); sascha@2561: sE.setAttribute("class", String.valueOf(sector.sector)); sascha@2561: sascha@2561: eE.appendChild(sE); sascha@2561: } sascha@2561: sascha@2561: esE.appendChild(eE); sascha@2561: } sascha@2561: } sascha@2561: sascha@2561: fixingsElement.appendChild(esE); sascha@2561: sascha@2561: document.appendChild(fixingsElement); sascha@2561: } aheinecke@6059: aheinecke@6059: public Range getExtent() { aheinecke@6059: return extent; aheinecke@6059: } sascha@2561: } sascha@2561: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :