ingo@2215: package de.intevation.flys.artifacts.model;
ingo@2215: 
ingo@2228: import java.util.ArrayList;
ingo@2228: import java.util.Date;
ingo@2228: import java.util.List;
ingo@2228: 
ingo@2215: import org.apache.log4j.Logger;
ingo@2215: 
ingo@2228: import de.intevation.flys.model.DischargeTable;
ingo@2219: import de.intevation.flys.model.Gauge;
ingo@2228: import de.intevation.flys.model.TimeInterval;
ingo@2219: 
ingo@2215: 
ingo@2215: /**
ingo@2215:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@2215:  */
ingo@2215: public class Calculation6 extends Calculation {
ingo@2215: 
ingo@2215:     private static final Logger logger = Logger.getLogger(Calculation6.class);
ingo@2215: 
ingo@2219:     private int      mode;
ingo@2228:     private long[]   timerange;
ingo@2219:     private double[] values;
ingo@2215: 
ingo@2219: 
ingo@2219:     public static final int MODE_W = 0;
ingo@2219:     public static final int MODE_Q = 1;
ingo@2219: 
ingo@4136:     public static final double SCALE = 1d;
ingo@2230: 
ingo@2219: 
ingo@2228:     public Calculation6(int mode, long[] timerange, double[] values) {
ingo@2219:         this.mode      = mode;
ingo@2219:         this.timerange = timerange;
ingo@2219:         this.values    = values;
ingo@2215:     }
ingo@2215: 
ingo@2215: 
ingo@2219:     public CalculationResult calculate(Gauge gauge) {
ingo@2219:         if (!checkParameters() || gauge == null) {
ingo@2219:             logger.warn("Parameters not valid for calculation.");
ingo@2219: 
ingo@2219:             return null;
ingo@2219:         }
ingo@2219: 
ingo@2219:         if (logger.isDebugEnabled()) {
ingo@2219:             debug();
ingo@2219:         }
ingo@2219: 
ingo@2311:         DischargeTable  refTable = fetchReferenceTable(gauge);
ingo@2228:         List<DischargeTable> dts = fetchDischargeTables(gauge);
ingo@2219: 
ingo@2304:         int numTables = dts.size();
ingo@2304: 
ingo@2304:         logger.debug("Take " + numTables + " into account.");
ingo@2304: 
ingo@2304:         if (numTables == 0) {
ingo@2304:             addProblem("cannot.find.hist.q.tables");
ingo@2304:         }
ingo@2228: 
ingo@2311:         WQTimerange[] wqt = prepareCalculationData(refTable, dts);
ingo@2228: 
ingo@2250:         logger.debug("Number of calculation results: " + wqt.length);
ingo@2250: 
ingo@2228:         return new CalculationResult(wqt, this);
ingo@2215:     }
ingo@2219: 
ingo@2219: 
ingo@2219:     protected boolean checkParameters() {
ingo@2219:         if (!(mode == MODE_W || mode == MODE_Q)) {
ingo@2219:             logger.warn("Invalid mode '" + mode + "' for calculation.");
ingo@2219:             return false;
ingo@2219:         }
ingo@2219: 
ingo@2219:         if (timerange == null || timerange.length < 2) {
ingo@2219:             logger.warn("Invalid timerange for calculation.");
ingo@2219:             return false;
ingo@2219:         }
ingo@2219: 
ingo@2219:         if (values == null || values.length == 0) {
ingo@2219:             logger.warn("No values for W or Q specified.");
ingo@2219:             return false;
ingo@2219:         }
ingo@2219: 
ingo@2219:         return true;
ingo@2219:     }
ingo@2219: 
ingo@2219: 
ingo@2311:     protected DischargeTable fetchReferenceTable(Gauge gauge) {
ingo@2311:         return gauge.fetchMasterDischargeTable();
ingo@2311:     }
ingo@2311: 
ingo@2311: 
ingo@2228:     protected List<DischargeTable> fetchDischargeTables(Gauge gauge) {
ingo@2228:         List<DischargeTable> relevant = new ArrayList<DischargeTable>();
ingo@2228:         List<DischargeTable> all      = gauge.getDischargeTables();
ingo@2228: 
ingo@2228:         for (DischargeTable dt: all) {
ingo@2228:             if (isDischargeTableRelevant(dt)) {
ingo@2228:                 relevant.add(dt);
ingo@2228:             }
ingo@2228:         }
ingo@2228: 
ingo@2228:         return relevant;
ingo@2228:     }
ingo@2228: 
ingo@2228: 
ingo@2228:     protected boolean isDischargeTableRelevant(DischargeTable dt) {
ingo@2228:         TimeInterval ti = dt.getTimeInterval();
ingo@2228: 
ingo@2598:         if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE || ti == null) {
ingo@2315:             return false;
ingo@2315:         }
ingo@2315: 
ingo@2228:         Date start     = ti.getStartTime();
ingo@2228:         long startTime = start.getTime();
ingo@2228: 
ingo@2228:         if (startTime >= timerange[0] && startTime <= timerange[1]) {
ingo@2228:             return true;
ingo@2228:         }
ingo@2228: 
ingo@2228:         Date stop     = ti.getStopTime();
ingo@2228:         long stopTime = stop != null ? stop.getTime() : -1l;
ingo@2228: 
ingo@2228:         if (stopTime >= timerange[0] && stopTime <= timerange[1]) {
ingo@2228:             return true;
ingo@2228:         }
ingo@2228: 
ingo@2228:         logger.debug("DischargeTable not in range: " + start + " -> " + stop);
ingo@2228: 
ingo@2228:         return false;
ingo@2228:     }
ingo@2228: 
ingo@2228: 
ingo@2311:     protected WQTimerange[] prepareCalculationData(
ingo@2311:         DischargeTable       refTable,
ingo@2311:         List<DischargeTable> dts
ingo@2311:     ) {
ingo@2311:         if (refTable == null) {
ingo@2311:             addProblem("cannot.find.hist.q.reftable");
ingo@2311:             return prepareSimpleData(dts);
ingo@2311:         }
ingo@2311:         else {
ingo@2311:             return prepareData(refTable, dts);
ingo@2311:         }
ingo@2311:     }
ingo@2311: 
ingo@2311: 
ingo@2311:     protected WQTimerange[] prepareSimpleData(List<DischargeTable> dts) {
ingo@2311:         List<WQTimerange> wqts =
ingo@2311:             new ArrayList<WQTimerange>(values.length);
ingo@2228: 
ingo@2228:         for (double value: values) {
ingo@2228:             logger.debug("Prepare data for value: " + value);
ingo@2228: 
ingo@2311:             String name      = mode == MODE_W ? "W=" + value : "Q=" + value;
ingo@2244:             WQTimerange wqt  = null;
ingo@2228: 
ingo@2228:             for (DischargeTable dt: dts) {
ingo@2315:                 Date[]   ti = prepareTimeInterval(dt);
ingo@2315:                 Timerange t = new Timerange(ti[0], ti[1]);
ingo@2228:                 double    w;
ingo@2228:                 double    q;
ingo@2228: 
ingo@2228:                 if (mode == MODE_W) {
ingo@2228:                     w = value;
ingo@4138:                     q = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);
ingo@2244: 
ingo@2244:                     if (Double.isNaN(q)) {
ingo@2244:                         logger.warn("Cannot find Q for W: " + w);
ingo@2315:                         addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
ingo@2244:                         continue;
ingo@2244:                     }
ingo@2228:                 }
ingo@2228:                 else {
ingo@2228:                     q = value;
ingo@2228:                     w = findValueForQ(dt, q);
ingo@2228:                 }
ingo@2228: 
ingo@2315:                 logger.debug("Q=" + q + " | W=" + w);
ingo@2230: 
ingo@2244:                 if (wqt == null) {
ingo@2244:                     wqt = new WQTimerange(name);
ingo@2244:                 }
ingo@2244: 
ingo@2228:                 wqt.add(w, q, t);
ingo@2228:             }
ingo@2228: 
ingo@2244:             if (wqt != null) {
ingo@2244:                 wqts.add(wqt);
ingo@2244:             }
ingo@2228:         }
ingo@2228: 
sascha@3452:         return wqts.toArray(new WQTimerange[wqts.size()]);
ingo@2228:     }
ingo@2228: 
ingo@2228: 
ingo@2311:     protected HistoricalWQTimerange[] prepareData(
ingo@2311:         DischargeTable       refTable,
ingo@2311:         List<DischargeTable> dts
ingo@2311:     ) {
ingo@2311:         List<HistoricalWQTimerange> wqts =
ingo@2311:             new ArrayList<HistoricalWQTimerange>(values.length);
ingo@2311: 
ingo@2311:         for (double value: values) {
ingo@2311:             logger.debug("Prepare data plus diff for value: " + value);
ingo@2311: 
ingo@2311:             String name = mode == MODE_W ? "W=" + value : "Q=" + value;
ingo@2311:             HistoricalWQTimerange wqt  = null;
ingo@2311: 
ingo@2311:             double ref;
ingo@2315:             double diff;
ingo@2311: 
ingo@2311:             if (refTable != null && mode == MODE_W) {
ingo@4138:                 ref = findValueForW(refTable, value, DischargeTables.MASTER_SCALE);
ingo@2311:             }
ingo@2311:             else if (refTable != null) {
ingo@2311:                 ref = findValueForQ(refTable, value);
ingo@2311:             }
ingo@2311:             else {
ingo@2311:                 ref = Double.NaN;
ingo@2311:             }
ingo@2311: 
ingo@2311:             for (DischargeTable dt: dts) {
ingo@2315:                 Date[] ti = prepareTimeInterval(dt);
ingo@2311: 
ingo@2315:                 Timerange t = new Timerange(ti[0] ,ti[1]);
ingo@2311:                 double    w;
ingo@2311:                 double    q;
ingo@2311: 
ingo@2311:                 if (mode == MODE_W) {
ingo@2315:                     w    = value;
ingo@4138:                     q    = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);
ingo@2311: 
ingo@2311:                     if (Double.isNaN(q)) {
ingo@2311:                         logger.warn("Cannot find Q for W: " + w);
ingo@2315:                         addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
ingo@2311:                         continue;
ingo@2311:                     }
ingo@2315: 
ingo@2315:                     diff = ref-q;
ingo@2311:                 }
ingo@2311:                 else {
ingo@2315:                     q    = value;
ingo@2315:                     w    = findValueForQ(dt, q);
ingo@2315:                     diff = ref-w;
ingo@2311:                 }
ingo@2311: 
ingo@2315:                 logger.debug("Q=" + q + " | W=" + w + " | Ref = " + ref);
ingo@2311: 
ingo@2311:                 if (wqt == null) {
ingo@2311:                     wqt = new HistoricalWQTimerange(name);
ingo@2311:                 }
ingo@2311: 
ingo@2315:                 wqt.add(w, q, diff, t);
ingo@2311:             }
ingo@2311: 
ingo@2311:             if (wqt != null) {
ingo@2311:                 wqts.add(wqt);
ingo@2311:             }
ingo@2311:         }
ingo@2311: 
ingo@2311:         return (HistoricalWQTimerange[])
ingo@2311:             wqts.toArray(new HistoricalWQTimerange[wqts.size()]);
ingo@2311:     }
ingo@2311: 
ingo@2311: 
ingo@2315:     protected Date[] prepareTimeInterval(DischargeTable dt) {
ingo@2315:         TimeInterval ti = dt.getTimeInterval();
ingo@2315: 
ingo@2315:         Date start = ti.getStartTime();
ingo@2315:         Date end   = ti.getStopTime();
ingo@2315: 
ingo@2315:         if (end == null) {
ingo@2315:             logger.warn("TimeInterval has no stop time set!");
ingo@2315: 
ingo@2315:             end = new Date();
ingo@2315:         }
ingo@2315: 
ingo@2315:         return new Date[] { start, end };
ingo@2315:     }
ingo@2315: 
ingo@2315: 
ingo@4138:     protected double findValueForW(DischargeTable dt, double w, double scale) {
ingo@4138:         double[][] vs = DischargeTables.loadDischargeTableValues(dt, scale);
sascha@2418:         double [] qs = DischargeTables.getQsForW(vs, w);
sascha@2418:         return qs.length == 0 ? Double.NaN : qs[0];
ingo@2228:     }
ingo@2228: 
ingo@2228: 
ingo@2228:     protected double findValueForQ(DischargeTable dt, double q) {
sascha@2418:         double[][] vs = DischargeTables.loadDischargeTableValues(dt, SCALE);
ingo@2228:         logger.warn("TODO: IMPLEMENT ME!");
ingo@2230: 
ingo@2228:         return 10;
ingo@2228:     }
ingo@2228: 
ingo@2228: 
ingo@2219:     /**
ingo@2219:      * Writes the parameters used for this calculation to logger.
ingo@2219:      */
ingo@2219:     public void debug() {
ingo@2219:         StringBuilder sb = new StringBuilder();
ingo@2219:         for (double value: values) {
ingo@2219:             sb.append(String.valueOf(value) + " ");
ingo@2219:         }
ingo@2219: 
ingo@2219:         logger.debug("========== Calculation6 ==========");
ingo@2219:         logger.debug("   Mode:         " + mode);
ingo@2219:         logger.debug("   Timerange:    " + timerange[0] + " - " + timerange[1]);
ingo@2219:         logger.debug("   Input values: " + sb.toString());
ingo@2219:         logger.debug("==================================");
ingo@2219:     }
ingo@2215: }
ingo@2215: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :