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.exports; ingo@2215: ingo@4176: import java.util.Date; ingo@4176: ingo@4176: import org.apache.log4j.Logger; teichmann@6144: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; gernotbelger@9123: import org.dive4elements.artifacts.CallContext; teichmann@6144: import org.dive4elements.river.artifacts.D4EArtifact; teichmann@6144: import org.dive4elements.river.artifacts.access.HistoricalDischargeAccess; teichmann@6144: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@6144: import org.dive4elements.river.artifacts.model.HistoricalWQTimerange; teichmann@6144: import org.dive4elements.river.artifacts.model.Timerange; teichmann@6144: import org.dive4elements.river.artifacts.model.WQTimerange; teichmann@6144: import org.dive4elements.river.jfree.StyledTimeSeries; teichmann@6905: import org.dive4elements.river.themes.ThemeDocument; teichmann@6144: import org.dive4elements.river.utils.RiverUtils; ingo@4176: import org.jfree.chart.plot.XYPlot; ingo@4176: import org.jfree.data.general.SeriesException; aheinecke@6142: import org.jfree.data.time.FixedMillisecond; ingo@4176: import org.jfree.data.time.RegularTimePeriod; ingo@4176: import org.jfree.data.time.TimeSeries; ingo@4176: import org.jfree.data.time.TimeSeriesCollection; ingo@4176: ingo@2215: /** ingo@2215: * @author Ingo Weinzierl ingo@2215: */ gernotbelger@9312: public class HistoricalDischargeCurveGenerator extends TimeseriesChartGenerator implements FacetTypes { ingo@2249: gernotbelger@9312: private static Logger log = Logger.getLogger(HistoricalDischargeCurveGenerator.class); ingo@4232: gernotbelger@9312: public static final String I18N_CHART_TITLE = "chart.historical.discharge.title"; ingo@4232: gernotbelger@9312: public static final String I18N_CHART_SUBTITLE = "chart.historical.discharge.subtitle"; tom@8856: gernotbelger@9312: public static final String I18N_XAXIS_LABEL = "chart.historical.discharge.xaxis.label"; gernotbelger@9312: gernotbelger@9312: public static final String I18N_YAXIS_LABEL = "chart.historical.discharge.yaxis.label"; gernotbelger@9312: gernotbelger@9312: public static final String I18N_YAXIS_SECOND_LABEL = "common.export.csv.header.q"; ingo@2249: ingo@2215: public static enum YAXIS { ingo@4232: W(0), Q(1); ingo@4232: ingo@2215: protected int idx; ingo@4232: gernotbelger@9312: private YAXIS(final int c) { gernotbelger@9312: this.idx = c; ingo@2215: } ingo@2215: } ingo@2215: ingo@2215: @Override ingo@2215: protected YAxisWalker getYAxisWalker() { ingo@2215: return new YAxisWalker() { ingo@4232: ingo@2215: @Override ingo@2215: public int length() { ingo@2215: return YAXIS.values().length; ingo@2215: } ingo@2215: ingo@2215: @Override gernotbelger@9312: public String getId(final int idx) { gernotbelger@9312: final YAXIS[] yaxes = YAXIS.values(); ingo@2215: return yaxes[idx].toString(); ingo@2215: } ingo@2215: }; ingo@2215: } ingo@2215: ingo@2215: @Override gernotbelger@9123: protected String getDefaultChartTitle(final CallContext context) { ingo@2249: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); ingo@2249: } ingo@2249: ingo@2249: @Override gernotbelger@9123: protected String getDefaultChartSubtitle(final CallContext context) { gernotbelger@9312: final D4EArtifact flys = getArtifact(); gernotbelger@9312: final Timerange evalTime = new HistoricalDischargeAccess(flys).getEvaluationTimerange(); ingo@4152: gernotbelger@9312: final Object[] args = new Object[] { RiverUtils.getReferenceGaugeName(flys), evalTime.getStart(), evalTime.getEnd() }; ingo@2249: ingo@2249: return msg(I18N_CHART_SUBTITLE, "", args); ingo@2215: } ingo@2215: ingo@2215: @Override gernotbelger@9123: protected String getDefaultXAxisLabel(final CallContext context) { ingo@2249: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); ingo@2215: } ingo@2215: ingo@2215: @Override gernotbelger@9312: protected String getDefaultYAxisLabel(final int pos) { ingo@2249: if (pos == 0) { ingo@2249: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); gernotbelger@9312: } else if (pos == 1) { ingo@2249: return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL); gernotbelger@9312: } else { ingo@2249: return "NO TITLE FOR Y AXIS: " + pos; ingo@2249: } ingo@2215: } ingo@2215: ingo@4176: @Override gernotbelger@9312: protected void adjustPlot(final XYPlot plot) { ingo@4176: super.adjustPlot(plot); ingo@4176: plot.setRangeZeroBaselineVisible(true); ingo@4176: } ingo@4176: christian@3409: @Override gernotbelger@9312: public void doOut(final ArtifactAndFacet artifactFacet, final ThemeDocument theme, final boolean visible) { gernotbelger@9312: final String name = artifactFacet.getFacetName(); gernotbelger@9556: String facetDescription = artifactFacet.getFacetDescription(); gernotbelger@9556: teichmann@8202: log.debug("HistoricalDischargeCurveGenerator.doOut: " + name); gernotbelger@9556: log.debug("Theme description is: " + facetDescription); ingo@2215: gernotbelger@9123: final CallContext context = getContext(); gernotbelger@9312: ingo@2215: if (name.equals(HISTORICAL_DISCHARGE_Q)) { gernotbelger@9556: doHistoricalDischargeOutQ(name, (D4EArtifact) artifactFacet.getArtifact(), artifactFacet.getData(context), facetDescription, theme, gernotbelger@9312: visible); gernotbelger@9312: } else if (name.equals(HISTORICAL_DISCHARGE_W)) { gernotbelger@9556: doHistoricalDischargeOutW(name, (D4EArtifact) artifactFacet.getArtifact(), artifactFacet.getData(context), facetDescription, theme, gernotbelger@9312: visible); gernotbelger@9312: } else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) { gernotbelger@9556: doHistoricalDischargeDifferenceOutQ(name, (D4EArtifact) artifactFacet.getArtifact(), artifactFacet.getData(context), facetDescription, gernotbelger@9312: theme, visible); gernotbelger@9312: } else if (name.equals(HISTORICAL_DISCHARGE_W_DIFF)) { gernotbelger@9556: doHistoricalDischargeDifferenceOutW(name, (D4EArtifact) artifactFacet.getArtifact(), artifactFacet.getData(context), facetDescription, gernotbelger@9312: theme, visible); gernotbelger@9312: } else if (FacetTypes.IS.MANUALPOINTS(name)) { gernotbelger@9312: final HistoricalDischargeAccess.EvaluationMode mode = new HistoricalDischargeAccess((D4EArtifact) getMaster()).getEvaluationMode(); gernotbelger@9312: final int axis = mode == HistoricalDischargeAccess.EvaluationMode.W ? YAXIS.Q.idx : YAXIS.W.idx; teichmann@7902: gernotbelger@9312: doPoints(artifactFacet.getData(context), artifactFacet, theme, visible, axis); gernotbelger@9312: } else { teichmann@8202: log.warn("doOut(): unknown facet name: " + name); ingo@4232: return; ingo@2215: } ingo@2215: } ingo@2215: gernotbelger@9556: protected void doHistoricalDischargeOutQ(final String facetName, final D4EArtifact artifact, final Object data, final String desc, final ThemeDocument theme, gernotbelger@9312: final boolean visible) { teichmann@8202: log.debug("doHistoricalDischargeOut(): description = " + desc); ingo@2311: gernotbelger@9312: final WQTimerange wqt = (WQTimerange) data; ingo@4232: gernotbelger@9556: final TimeSeriesCollection tsc = newTimeSeriesCollection(facetName, wqt.getTimeranges(), wqt.getQs(), theme, desc); gernotbelger@9556: gernotbelger@9556: addAxisDataset(tsc, YAXIS.Q.idx, visible); gernotbelger@9556: } gernotbelger@9556: gernotbelger@9556: protected void doHistoricalDischargeOutW(final String facetName, final D4EArtifact artifact, final Object data, final String desc, final ThemeDocument theme, gernotbelger@9556: final boolean visible) { gernotbelger@9556: log.debug("doHistoricalDischargeOut(): description = " + desc); gernotbelger@9556: gernotbelger@9556: final WQTimerange wqt = (WQTimerange) data; gernotbelger@9556: gernotbelger@9556: final TimeSeriesCollection tsc = newTimeSeriesCollection(facetName, wqt.getTimeranges(), wqt.getWs(), theme, desc); ingo@4232: ingo@4232: addAxisDataset(tsc, YAXIS.W.idx, visible); ingo@4232: } ingo@4232: gernotbelger@9556: protected void doHistoricalDischargeDifferenceOutQ(final String facetName, final D4EArtifact artifact, final Object data, final String desc, final ThemeDocument theme, gernotbelger@9312: final boolean visible) { teichmann@8202: log.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); ingo@2311: gernotbelger@9312: final HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; ingo@2311: gernotbelger@9556: final TimeSeriesCollection tsc = newTimeSeriesCollection(facetName, wqt.getTimeranges(), wqt.getDiffs(), theme, desc); ingo@2240: ingo@4232: addAxisDataset(tsc, YAXIS.Q.idx, visible); ingo@2240: } ingo@2240: gernotbelger@9556: protected void doHistoricalDischargeDifferenceOutW(final String facetName, final D4EArtifact artifact, final Object data, final String desc, final ThemeDocument theme, gernotbelger@9312: final boolean visible) { teichmann@8202: log.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); ingo@4232: gernotbelger@9312: final HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; ingo@4232: gernotbelger@9556: final TimeSeriesCollection tsc = newTimeSeriesCollection(facetName, wqt.getTimeranges(), wqt.getDiffs(), theme, desc); ingo@4232: ingo@4232: addAxisDataset(tsc, YAXIS.W.idx, visible); ingo@4232: } ingo@2240: ingo@2240: /** ingo@2240: * Creates a new TimeSeriesCollection with a single TimeSeries. The ingo@2240: * TimeSeries will consist of two RegularTimePeriods for each W/Q value ingo@2240: * provided by wqt. This has the effect, that the line in the chart ingo@2240: * looks like a "step chart". ingo@2240: */ gernotbelger@9556: protected TimeSeriesCollection newTimeSeriesCollection(final String facetName, final Timerange[] timeranges, final double[] values, final ThemeDocument theme, final String desc) { teichmann@8202: log.debug("Create new TimeSeriesCollection for: " + desc); ingo@2240: gernotbelger@9312: final TimeSeriesCollection tsc = new TimeSeriesCollection(); gernotbelger@9556: final TimeSeries series = new StyledTimeSeries(facetName, desc, theme); ingo@2240: ingo@2311: for (int i = 0, n = timeranges.length; i < n; i++) { gernotbelger@9312: final RegularTimePeriod[] rtp = newRegularTimePeriod(timeranges[i]); ingo@2240: ingo@2240: try { ingo@2311: if (Double.isNaN(values[i])) { teichmann@8202: log.warn("Skip TimePeriod because value is NaN."); ingo@2243: continue; ingo@2243: } ingo@2243: ingo@2311: series.add(rtp[0], values[i]); ingo@2311: series.add(rtp[1], values[i]); ingo@2243: teichmann@8202: if (log.isDebugEnabled()) { teichmann@8202: log.debug("added Item to TimeSeries:"); teichmann@8202: log.debug(" TimePeriod: " + rtp[0] + " - " + rtp[1]); teichmann@8202: log.debug(" Value: " + values[i]); ingo@2243: } ingo@2240: } gernotbelger@9312: catch (final SeriesException se) { teichmann@8202: log.warn("Error while adding TimePeriod: " + se); ingo@2240: } ingo@2240: } ingo@2240: ingo@2240: tsc.addSeries(series); ingo@2240: ingo@2240: return tsc; ingo@2240: } ingo@2240: ingo@2240: /** tom@8856: * Create array that consists of two tom@8856: * FixedMillisecond periods [start, end]. teichmann@4736: * ingo@4232: * @param timerange ingo@4232: * Supports start and end time. teichmann@4736: * aheinecke@6156: * @return an array with two FixedMillisecond periods [start, end]. ingo@2240: */ gernotbelger@9312: protected RegularTimePeriod[] newRegularTimePeriod(final Timerange timerange) { gernotbelger@9312: final Date start = new Date(timerange.getStart()); gernotbelger@9312: final Date end = new Date(timerange.getEnd() - 1000 * 60 * 60 * 24); ingo@2240: gernotbelger@9312: return new RegularTimePeriod[] { new FixedMillisecond(start), new FixedMillisecond(end) }; ingo@2215: } ingo@2215: } ingo@2215: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :