sascha@2561: package de.intevation.flys.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.HashMap;
sascha@2561: import java.util.List;
sascha@2561: import java.util.Map;
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: 
sascha@2561: public class FixingsOverview
sascha@2561: implements   Serializable
sascha@2561: {
sascha@2561:     private static Logger log = Logger.getLogger(FixingsOverview.class);
sascha@2561: 
sascha@2561:     public static final double EPSILON  = 1e-5;
sascha@2561:     public static final double EPSILON2 = 1e-1;
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: 
sascha@2561:     public static final String SQL_GAUGES =
sascha@2561:         "SELECT" +
sascha@2561:         "    g.id AS gauge_id," +
sascha@2561:         "    r.a  AS a," +
sascha@2561:         "    r.b  AS b " +
sascha@2561:         "FROM gauges g" +
sascha@2561:         "    JOIN ranges r ON g.range_id = r.id " +
sascha@2561:         "WHERE" +
sascha@2561:         "    g.river_id = :river_id " +
sascha@2561:         "ORDER BY r.a";
sascha@2561: 
sascha@2561:     public static final String SQL_DISCHARGE_SECTORS =
sascha@2561:         "SELECT" +
sascha@2561:         "    g.id                            AS gauge_id," +
sascha@2561:         "    nmv.name                        AS name," +
sascha@2561:         "    CAST(mv.value AS NUMERIC(38,2)) AS value " +
sascha@2561:         "FROM gauges g" +
sascha@2561:         "    JOIN main_values       mv  ON g.id = mv.gauge_id" +
sascha@2561:         "    JOIN named_main_values nmv ON nmv.id = mv.named_value_id" +
sascha@2561:         "    JOIN main_value_types  mvt ON nmv.type_id = mvt.id " +
sascha@2561:         "WHERE" +
sascha@2561:         "    mvt.name = 'Q' AND (" +
sascha@2561:         "        nmv.name = 'MNQ'      OR" +
sascha@2561:         "        nmv.name LIKE 'MNQ(%' OR" +
sascha@2561:         "        nmv.name = 'MQ'       OR" +
sascha@2561:         "        nmv.name LIKE 'MQ(%'  OR" +
sascha@2561:         "        nmv.name = 'MHQ'      OR" +
sascha@2561:         "        nmv.name LIKE 'MHQ(%' OR" +
sascha@2561:         "        nmv.name = 'HQ5'      OR" +
sascha@2561:         "        nmv.name LIKE 'HQ5(%') AND" +
sascha@2561:         "    g.river_id = :river_id " +
sascha@2561:         "ORDER BY" +
sascha@2561:         "    g.id";
sascha@2561: 
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: 
sascha@2561:     public static final String SQL_FIXING_COLUMNS =
sascha@2561:         "SELECT" +
sascha@2561:         "    wc.id         AS wst_column_id," +
sascha@2561:         "    ti.start_time AS start_time," +
sascha@2561:         "    wc.name       AS name " +
sascha@2561:         "FROM wst_columns wc" +
sascha@2561:         "    JOIN time_intervals ti ON wc.time_interval_id = ti.id " +
sascha@2561:         "WHERE" +
sascha@2561:         "    wc.wst_id = :wst_id " +
sascha@2561:         "ORDER BY position";
sascha@2561: 
sascha@2561:     public static final String SQL_FIXING_COLUMN_Q_RANGES =
sascha@2561:         "SELECT" +
sascha@2561:         "    wqr.q AS q," +
sascha@2561:         "    r.a   AS start_km," +
sascha@2561:         "    r.b   AS stop_km " +
sascha@2561:         "FROM wst_column_q_ranges wcqr" +
sascha@2561:         "    JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" +
sascha@2561:         "    JOIN ranges       r   ON wqr.range_id        = r.id " +
sascha@2561:         "WHERE" +
sascha@2561:         "    wcqr.wst_column_id = :column_id " +
sascha@2561:         "ORDER BY r.a";
sascha@2561: 
sascha@2561:     public static final String SQL_FIXING_COLUMN_KM_RANGE =
sascha@2561:         "SELECT" +
sascha@2561:         "    MIN(position) AS start_km," +
sascha@2561:         "    MAX(position) AS stop_km " +
sascha@2561:         "FROM" +
sascha@2561:         "    wst_column_values " +
sascha@2562:         "WHERE" +
sascha@2561:         "    wst_column_id = :column_id";
sascha@2561: 
sascha@2561:     public static class Range implements Serializable {
sascha@2561: 
sascha@2561:         protected double start;
sascha@2561:         protected double end;
sascha@2561: 
sascha@2561:         public Range() {
sascha@2561:         }
sascha@2561: 
sascha@2561:         public Range(double start, double end) {
sascha@2561:             this.start = start;
sascha@2561:             this.end   = end;
sascha@2561:         }
sascha@2561: 
sascha@2562:         public double getStart() {
sascha@2562:             return start;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public double getEnd() {
sascha@2562:             return end;
sascha@2562:         }
sascha@2562: 
sascha@2561:         public boolean disjoint(Range other) {
sascha@2561:             return start > other.end || other.start > end;
sascha@2561:         }
sascha@2561: 
sascha@2562:         public boolean intersects(Range other) {
sascha@2562:             return !disjoint(other);
sascha@2562:         }
sascha@2562: 
sascha@2565:         public void extend(Range other) {
sascha@2565:             if (other.start < start) start = other.start;
sascha@2565:             if (other.end   > end  ) end   = other.end;
sascha@2565:         }
sascha@2565: 
sascha@2561:         public boolean clip(Range other) {
sascha@2561:             if (disjoint(other)) return false;
sascha@2561: 
sascha@2561:             if (other.start > start) start = other.start;
sascha@2561:             if (other.end   < end  ) end   = other.end;
sascha@2561: 
sascha@2561:             return true;
sascha@2561:         }
sascha@2561: 
sascha@2561:         public boolean inside(double x) {
sascha@2561:             return x > start-EPSILON && x < end+EPSILON;
sascha@2561:         }
sascha@2561:     } // class Range
sascha@2561: 
sascha@2561:     public static class GaugeRange extends Range {
sascha@2561: 
sascha@2561:         private static final class Sector implements Serializable {
sascha@2561: 
sascha@2561:             int    sector;
sascha@2561:             double value;
sascha@2561: 
sascha@2561:             Sector(int sector, double value) {
sascha@2561:                 this.sector = sector;
sascha@2561:                 this.value  = value;
sascha@2561:             }
sascha@2561: 
sascha@2561:         } // class Sector
sascha@2561: 
sascha@2561:         protected int gaugeId;
sascha@2561: 
sascha@2561:         protected Map<String, Double> mainValues;
sascha@2561:         protected List<Sector> sectors;
sascha@2561: 
sascha@2561:         public GaugeRange() {
sascha@2561:         }
sascha@2561: 
sascha@2561:         public GaugeRange(double start, double end, int gaugeId) {
sascha@2561:             super(start, end);
sascha@2561:             this.gaugeId = gaugeId;
sascha@2561:             mainValues = new HashMap<String, Double>();
sascha@2561:             sectors = new ArrayList<Sector>(3);
sascha@2561:         }
sascha@2561: 
sascha@2561:         public void addMainValue(String label, Double value) {
sascha@2561:             int idx = label.indexOf('(');
sascha@2561:             if (idx >= 0) {
sascha@2561:                 label = label.substring(0, idx);
sascha@2561:             }
sascha@2561:             mainValues.put(label, value);
sascha@2561:         }
sascha@2561: 
sascha@2561:         protected Double getMainValue(String label) {
sascha@2561:             Double v = mainValues.get(label);
sascha@2561:             if (v == null) {
sascha@2561:                 log.warn("Missing main value '" 
sascha@2561:                     + label + "' for gauge " + gaugeId);
sascha@2561:             }
sascha@2561:             return v;
sascha@2561:         }
sascha@2561: 
sascha@2561:         public void buildClasses() {
sascha@2561:             Double mnq = getMainValue("MNQ");
sascha@2561:             Double mq  = getMainValue("MQ");
sascha@2561:             Double mhq = getMainValue("MHQ");
sascha@2561:             Double hq5 = getMainValue("HQ5");
sascha@2561: 
sascha@2561:             Double [][] pairs = {
sascha@2561:                 { mnq,  mq },
sascha@2561:                 {  mq, mhq },
sascha@2561:                 { hq5, hq5 } };
sascha@2561: 
sascha@2561:             for (int c = 0; c < pairs.length; ++c) {
sascha@2561:                 Double [] pair = pairs[c];
sascha@2561:                 if (pair[0] != null && pair[1] != null) {
sascha@2561:                     double value = 0.5*(pair[0] + pair[1]);
sascha@2561:                     sectors.add(new Sector(c, value));
sascha@2561:                 }
sascha@2561:             }
sascha@2561:         }
sascha@2561: 
sascha@2561:         public int classify(double value) {
sascha@2561:             for (Sector sector: sectors) {
sascha@2561:                 if (value < sector.value) {
sascha@2561:                     return sector.sector;
sascha@2561:                 }
sascha@2561:             }
sascha@2561:             return sectors.size();
sascha@2561:         }
sascha@2561:     } // class GaugeRange
sascha@2561: 
sascha@2562:     public static class GaugeFinder {
sascha@2562: 
sascha@2562:         protected List<GaugeRange> gauges;
sascha@2562:         protected boolean          isKmUp;
sascha@2562: 
sascha@2562:         public GaugeFinder(List<GaugeRange> gauges) {
sascha@2562:             this(gauges, true);
sascha@2562:         }
sascha@2562: 
sascha@2562:         public GaugeFinder(
sascha@2562:             List<GaugeRange> gauges,
sascha@2562:             boolean          isKmUp
sascha@2562:         ) {
sascha@2562:             this.gauges = gauges;
sascha@2562:             this.isKmUp = isKmUp;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public boolean getIsKmUp() {
sascha@2562:             return isKmUp;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public void setIsKmUp(boolean isKmUp) {
sascha@2562:             this.isKmUp = isKmUp;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public GaugeRange find(Range range) {
sascha@2562:             double km = isKmUp ? range.start : range.end;
sascha@2562:             for (GaugeRange gauge: gauges) {
sascha@2562:                 if (gauge.inside(km)) {
sascha@2562:                     return gauge;
sascha@2562:                 }
sascha@2562:             }
sascha@2562:             return null;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public GaugeRange find(int gaugeId) {
sascha@2562:             for (GaugeRange gauge: gauges) {
sascha@2562:                 if (gauge.gaugeId == gaugeId) {
sascha@2562:                     return gauge;
sascha@2562:                 }
sascha@2562:             }
sascha@2562:             return null;
sascha@2562:         }
sascha@2562: 
sascha@2562:         public boolean loadDischargeSectors(Session session, int riverId) {
sascha@2562: 
sascha@2562:             SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS)
sascha@2562:                 .addScalar("gauge_id", StandardBasicTypes.INTEGER)
sascha@2562:                 .addScalar("name",     StandardBasicTypes.STRING)
sascha@2562:                 .addScalar("value",    StandardBasicTypes.DOUBLE);
sascha@2562: 
sascha@2562:             query.setInteger("river_id", riverId);
sascha@2562: 
sascha@2562:             List<Object []> list = query.list();
sascha@2562: 
sascha@2562:             if (list.isEmpty()) {
sascha@2562:                 log.warn("River " + riverId + " has no discharge sectors.");
sascha@2562:                 return false;
sascha@2562:             }
sascha@2562: 
sascha@2562:             GaugeRange gauge = null;
sascha@2562: 
sascha@2562:             for (Object [] row: list) {
sascha@2562:                 int    gaugeId = (Integer)row[0];
sascha@2562:                 String label   = (String) row[1];
sascha@2562:                 Double value   = (Double) row[2];
sascha@2562: 
sascha@2562:                 if (gauge == null || gauge.gaugeId != gaugeId) {
sascha@2562:                     if ((gauge = find(gaugeId)) == null) {
sascha@2562:                         log.warn("Cannot find gauge for id " + gaugeId + ".");
sascha@2562:                         continue;
sascha@2562:                     }
sascha@2562:                 }
sascha@2562: 
sascha@2562:                 gauge.addMainValue(label, value);
sascha@2562:             }
sascha@2562: 
sascha@2562:             for (GaugeRange g: gauges) {
sascha@2562:                 g.buildClasses();
sascha@2562:             }
sascha@2562: 
sascha@2562:             return true;
sascha@2562:         }
sascha@2562:     } // class GaugeFinder
sascha@2562: 
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@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@2561:         public boolean enlarge(SectorRange other) {
sascha@2561:             if (sector == other.sector
sascha@2561:             && Math.abs(end-other.start) < EPSILON2) {
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<Column> DATE_CMP =
sascha@2561:             new Comparator<Column>() {
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<SectorRange> 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@2561:                 
sascha@2562:                 sectors = new ArrayList<SectorRange>();
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@2562:             public List<SectorRange> getSectors() {
sascha@2562:                 return sectors;
sascha@2562:             }
sascha@2561: 
sascha@2563:             public List<SectorRange> getSectors(Range range) {
sascha@2563: 
sascha@2563:                 List<SectorRange> result =
sascha@2563:                     new ArrayList<SectorRange>(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@2562:             public void buildSectors(GaugeRange gauge, List<QRange> qRanges) {
sascha@2561: 
sascha@2561:                 for (QRange qRange: qRanges) {
sascha@2561:                     SectorRange sector = new SectorRange(
sascha@2561:                         qRange.start, qRange.end,
sascha@2561:                         gauge.classify(qRange.q));
sascha@2561:                     if (sectors.isEmpty()
sascha@2561:                     || !sectors.get(sectors.size()-1).enlarge(sector)) {
sascha@2561:                         sectors.add(sector);
sascha@2561:                     }
sascha@2561:                 }
sascha@2561:             }
sascha@2561: 
sascha@2561:             public void loadKmRange(SQLQuery query) {
sascha@2561:                 query.setInteger("column_id", columnId);
sascha@2561: 
sascha@2561:                 List<Object []> kms = query.list();
sascha@2561: 
sascha@2561:                 if (kms.isEmpty()) {
sascha@2561:                     log.warn("No km range for column " + columnId + ".");
sascha@2561:                 }
sascha@2561:                 else {
sascha@2561:                     Object [] obj = kms.get(0);
sascha@2561:                     start = (Double)obj[0];
sascha@2561:                     end   = (Double)obj[1];
sascha@2561:                 }
sascha@2561:             }
sascha@2561: 
sascha@2562:             public void loadQRanges(
sascha@2562:                 SQLQuery    query,
sascha@2562:                 GaugeFinder gaugeFinder
sascha@2562:             ) {
sascha@2561:                 query.setInteger("column_id", columnId);
sascha@2561:                 List<Object []> list = query.list();
sascha@2561: 
sascha@2562:                 List<QRange> qRanges = new ArrayList<QRange>(list.size());
sascha@2562: 
sascha@2561:                 for (Object [] row: list) {
sascha@2561:                     double q     = (Double)row[0];
sascha@2561:                     double start = (Double)row[1];
sascha@2561:                     double end   = (Double)row[2];
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@2562:                 GaugeRange gauge = gaugeFinder.find(this);
sascha@2562: 
sascha@2562:                 if (gauge != null) {
sascha@2562:                     buildSectors(gauge, qRanges);
sascha@2562:                 }
sascha@2562:                 else {
sascha@2562:                     log.warn("No gauge found for column " + columnId + ".");
sascha@2562:                 }
sascha@2561:             }
sascha@2561:         } // class Column
sascha@2561: 
sascha@2562:         protected int          wstId;
sascha@2562:         protected String       description;
sascha@2561:         protected List<Column> 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<Column>();
sascha@2561:         }
sascha@2561: 
sascha@2561:         public void loadColumns(SQLQuery query) {
sascha@2561:             query.setInteger("wst_id", wstId);
sascha@2561:             List<Object []> list = query.list();
sascha@2561:             for (Object [] row: list) {
sascha@2561:                 int    columnId  = (Integer)row[0];
sascha@2561:                 Date   startTime = (Date)   row[1];
sascha@2561:                 String name      = (String) row[2];
sascha@2561:                 columns.add(new Column(columnId, startTime, name));
sascha@2561:             }
sascha@2561:         }
sascha@2561: 
sascha@2561:         public void loadColumnsKmRange(SQLQuery query) {
sascha@2561:             for (Column column: columns) {
sascha@2561:                 column.loadKmRange(query);
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(
sascha@2562:             SQLQuery    query,
sascha@2562:             GaugeFinder gaugeFinder
sascha@2562:         ) {
sascha@2561:             for (Column column: columns) {
sascha@2562:                 column.loadQRanges(query, gaugeFinder);
sascha@2561:             }
sascha@2561:         }
sascha@2561: 
sascha@2563:         public void addAllColumns(
sascha@2563:             List<Column> allColumns,
sascha@2563:             Range        range,
sascha@2563:             Filter       filter
sascha@2563:         ) {
sascha@2562:             for (Column column: columns) {
sascha@2613:                 if ((range == null || column.intersects(range)) 
sascha@2613:                 && (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<Fixing> fixings;
sascha@2562:     protected Range        extent;
sascha@2561: 
sascha@2561:     public FixingsOverview() {
sascha@2561:         fixings = new ArrayList<Fixing>();
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<Object []> 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@2562:     protected GaugeFinder loadGauges(Session session) {
sascha@2561:         SQLQuery query = session.createSQLQuery(SQL_GAUGES)
sascha@2561:             .addScalar("gauge_id", StandardBasicTypes.INTEGER)
sascha@2561:             .addScalar("a",        StandardBasicTypes.DOUBLE)
sascha@2561:             .addScalar("b",        StandardBasicTypes.DOUBLE);
sascha@2561: 
sascha@2561:         query.setInteger("river_id", riverId);
sascha@2561: 
sascha@2561:         List<Object []> list = query.list();
sascha@2561: 
sascha@2561:         if (list.isEmpty()) {
sascha@2561:             log.warn("River " + riverId + " has no gauges.");
sascha@2562:             return null;
sascha@2561:         }
sascha@2561: 
sascha@2562:         List<GaugeRange> gauges = new ArrayList<GaugeRange>();
sascha@2562: 
sascha@2561:         for (Object [] row: list) {
sascha@2561:             int    gaugeId = (Integer)row[0];
sascha@2561:             double start   = (Double) row[1];
sascha@2561:             double end     = (Double) row[2];
sascha@2561:             GaugeRange gauge = new GaugeRange(start, end, gaugeId);
sascha@2561:             gauges.add(gauge);
sascha@2561:         }
sascha@2561: 
sascha@2562:         return new GaugeFinder(gauges, isKmUp);
sascha@2561:     }
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<Object []> 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) {
sascha@2561:         SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS)
sascha@2561:             .addScalar("wst_column_id", StandardBasicTypes.INTEGER)
sascha@2561:             .addScalar("start_time",    StandardBasicTypes.DATE)
sascha@2561:             .addScalar("name",          StandardBasicTypes.STRING);
sascha@2561: 
sascha@2561:         for (Fixing fixing: fixings) {
sascha@2561:             fixing.loadColumns(query);
sascha@2561:         }
sascha@2561:     }
sascha@2561: 
sascha@2561:     protected void loadFixingsColumnsKmRange(Session session) {
sascha@2561:         SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE)
sascha@2561:             .addScalar("start_km", StandardBasicTypes.DOUBLE)
sascha@2561:             .addScalar("stop_km",  StandardBasicTypes.DOUBLE);
sascha@2561: 
sascha@2561:         for (Fixing fixing: fixings) {
sascha@2561:             fixing.loadColumnsKmRange(query);
sascha@2561:         }
sascha@2561:     }
sascha@2561: 
sascha@2562:     protected void loadFixingsColumnsQRanges(
sascha@2562:         Session     session,
sascha@2562:         GaugeFinder gaugeFinder
sascha@2562:     ) {
sascha@2561:         SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES)
sascha@2561:             .addScalar("q",        StandardBasicTypes.DOUBLE)
sascha@2561:             .addScalar("start_km", StandardBasicTypes.DOUBLE)
sascha@2561:             .addScalar("stop_km",  StandardBasicTypes.DOUBLE);
sascha@2561: 
sascha@2561:         for (Fixing fixing: fixings) {
sascha@2562:             fixing.loadColumnsQRanges(query, 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@2562:         GaugeFinder gaugeFinder = loadGauges(session);
sascha@2561: 
sascha@2562:         if (gaugeFinder == null
sascha@2562:         || !gaugeFinder.loadDischargeSectors(session, riverId)) {
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<Fixing.Filter> children;
sascha@2563: 
sascha@2563:         public ComponentFilter(List<Fixing.Filter> children) {
sascha@2563:             this.children = children;
sascha@2563:         }
sascha@2563:     } // class ComponentFilter
sascha@2563: 
sascha@2563:     public static class OrFilter extends ComponentFilter {
sascha@2563: 
sascha@2563:         public OrFilter(List<Fixing.Filter> 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@2563:         public AndFilter(List<Fixing.Filter> 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: 
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@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();
sascha@2563:                 if (v >= min && v <= max) {
sascha@2563:                     return true;
sascha@2563:                 }
sascha@2563:             }
sascha@2563:             return false;
sascha@2563:         }
sascha@2563:     } // class SectorRangeFilter
sascha@2563: 
sascha@2561:     public void generateOverview(Document document) {
sascha@2563:         generateOverview(document, FULL_EXTENT, ACCEPT);
sascha@2562:     }
sascha@2562: 
sascha@2608:     public List<Fixing.Column> filter(Range range, Fixing.Filter filter) {
sascha@2561:         List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>();
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@2608:     public void generateOverview(
sascha@2608:         Document      document,
sascha@2608:         Range         range,
sascha@2608:         Fixing.Filter filter
sascha@2608:     ) {
sascha@2608:         List<Fixing.Column> 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@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<SectorRange> sectors = column.getSectors(range);
sascha@2561: 
sascha@2561:             if (!sectors.isEmpty()) {
sascha@2561:                 Element eE = document.createElement("event");
sascha@2561:                 eE.setAttribute("name",
sascha@2561:                     String.valueOf(column.getFixing().description));
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:     }
sascha@2561: }
sascha@2561: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :