teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5863: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5863: * 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; ingo@4176: import org.jfree.chart.plot.XYPlot; ingo@4176: import org.jfree.data.general.SeriesException; ingo@4176: import org.jfree.data.time.Day; 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: import org.w3c.dom.Document; ingo@4176: teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; teichmann@5831: import org.dive4elements.river.artifacts.FLYSArtifact; teichmann@5831: import org.dive4elements.river.artifacts.access.HistoricalDischargeAccess; teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@5831: import org.dive4elements.river.artifacts.model.HistoricalWQTimerange; teichmann@5831: import org.dive4elements.river.artifacts.model.Timerange; teichmann@5831: import org.dive4elements.river.artifacts.model.WQTimerange; teichmann@5831: import org.dive4elements.river.jfree.StyledTimeSeries; teichmann@5865: import org.dive4elements.river.utils.RiverUtils; ingo@2215: ingo@2215: ingo@2215: /** ingo@2215: * @author Ingo Weinzierl ingo@2215: */ ingo@4232: public class HistoricalDischargeCurveGenerator extends TimeseriesChartGenerator ingo@4232: implements FacetTypes { ingo@2249: ingo@4232: private static Logger logger = Logger ingo@4232: .getLogger(HistoricalDischargeCurveGenerator.class); ingo@2249: ingo@4232: public static final String I18N_CHART_TITLE = "chart.historical.discharge.title"; ingo@2249: ingo@4232: public static final String I18N_CHART_SUBTITLE = "chart.historical.discharge.subtitle"; ingo@2249: ingo@4232: public static final String I18N_XAXIS_LABEL = "chart.historical.discharge.xaxis.label"; ingo@4232: ingo@4232: public static final String I18N_YAXIS_LABEL = "chart.historical.discharge.yaxis.label"; ingo@4232: ingo@4232: public static final String I18N_YAXIS_SECOND_LABEL = "chart.historical.discharge.yaxis.second.label"; ingo@2249: ingo@2215: public static enum YAXIS { ingo@4232: W(0), Q(1); ingo@4232: ingo@2215: protected int idx; ingo@4232: ingo@2215: private YAXIS(int c) { ingo@2215: 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 ingo@2215: public String getId(int idx) { ingo@2215: YAXIS[] yaxes = YAXIS.values(); ingo@2215: return yaxes[idx].toString(); ingo@2215: } ingo@2215: }; ingo@2215: } ingo@2215: ingo@2215: @Override ingo@2215: protected String getDefaultChartTitle() { ingo@2249: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); ingo@2249: } ingo@2249: ingo@2249: @Override ingo@2249: protected String getDefaultChartSubtitle() { ingo@4232: FLYSArtifact flys = (FLYSArtifact) master; ingo@4232: Timerange evalTime = new HistoricalDischargeAccess(flys) ingo@4232: .getEvaluationTimerange(); ingo@4152: teichmann@5865: Object[] args = new Object[] { RiverUtils.getReferenceGaugeName(flys), ingo@4232: evalTime.getStart(), evalTime.getEnd() }; ingo@2249: ingo@2249: return msg(I18N_CHART_SUBTITLE, "", args); ingo@2215: } ingo@2215: ingo@2215: @Override ingo@2215: protected String getDefaultXAxisLabel() { ingo@2249: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); ingo@2215: } ingo@2215: ingo@2215: @Override ingo@2215: protected String getDefaultYAxisLabel(int pos) { ingo@2249: if (pos == 0) { ingo@2249: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); ingo@2249: } ingo@2249: else if (pos == 1) { ingo@2249: return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL); ingo@2249: } ingo@2249: else { ingo@2249: return "NO TITLE FOR Y AXIS: " + pos; ingo@2249: } ingo@2215: } ingo@2215: ingo@4176: @Override ingo@4176: protected void adjustPlot(XYPlot plot) { ingo@4176: super.adjustPlot(plot); ingo@4176: plot.setRangeZeroBaselineVisible(true); ingo@4176: } ingo@4176: christian@3409: @Override ingo@4232: public void doOut(ArtifactAndFacet artifactFacet, Document theme, ingo@4232: boolean visible) { ingo@2215: String name = artifactFacet.getFacetName(); ingo@2215: logger.debug("HistoricalDischargeCurveGenerator.doOut: " + name); ingo@4232: logger.debug("Theme description is: " ingo@4232: + artifactFacet.getFacetDescription()); ingo@2215: ingo@2215: if (name.equals(HISTORICAL_DISCHARGE_Q)) { ingo@4232: doHistoricalDischargeOutQ( ingo@2215: (FLYSArtifact) artifactFacet.getArtifact(), ingo@2215: artifactFacet.getData(context), ingo@4232: artifactFacet.getFacetDescription(), theme, visible); ingo@2215: } ingo@4232: else if (name.equals(HISTORICAL_DISCHARGE_W)) { ingo@4232: doHistoricalDischargeOutW( ingo@2311: (FLYSArtifact) artifactFacet.getArtifact(), ingo@2311: artifactFacet.getData(context), ingo@4232: artifactFacet.getFacetDescription(), theme, visible); ingo@4232: } ingo@4232: else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) { ingo@4232: doHistoricalDischargeDifferenceOutQ( ingo@4232: (FLYSArtifact) artifactFacet.getArtifact(), ingo@4232: artifactFacet.getData(context), ingo@4232: artifactFacet.getFacetDescription(), theme, visible); ingo@4232: } ingo@4232: else if (name.equals(HISTORICAL_DISCHARGE_W_DIFF)) { ingo@4232: doHistoricalDischargeDifferenceOutW( ingo@4232: (FLYSArtifact) artifactFacet.getArtifact(), ingo@4232: artifactFacet.getData(context), ingo@4232: artifactFacet.getFacetDescription(), theme, visible); ingo@2311: } raimund@2633: else if (FacetTypes.IS.MANUALPOINTS(name)) { ingo@4232: doPoints(artifactFacet.getData(context), artifactFacet, theme, ingo@4232: visible, YAXIS.Q.idx); raimund@2633: } ingo@2215: else { ingo@4232: logger.warn("doOut(): unknown facet name: " + name); ingo@4232: return; ingo@2215: } ingo@2215: } ingo@2215: ingo@4232: protected void doHistoricalDischargeOutQ(FLYSArtifact artifact, ingo@4232: Object data, String desc, Document theme, boolean visible) { ingo@2215: logger.debug("doHistoricalDischargeOut(): description = " + desc); ingo@2240: ingo@2240: WQTimerange wqt = (WQTimerange) data; ingo@2240: ingo@4232: TimeSeriesCollection tsc = newTimeSeriesCollection(wqt.getTimeranges(), ingo@4232: wqt.getQs(), theme, desc); ingo@2311: ingo@4232: addAxisDataset(tsc, YAXIS.Q.idx, visible); ingo@2311: } ingo@2311: ingo@4232: protected void doHistoricalDischargeOutW(FLYSArtifact artifact, ingo@4232: Object data, String desc, Document theme, boolean visible) { ingo@4232: logger.debug("doHistoricalDischargeOut(): description = " + desc); ingo@2311: ingo@4232: WQTimerange wqt = (WQTimerange) data; ingo@4232: ingo@4232: TimeSeriesCollection tsc = newTimeSeriesCollection(wqt.getTimeranges(), ingo@4232: wqt.getWs(), theme, desc); ingo@4232: ingo@4232: addAxisDataset(tsc, YAXIS.W.idx, visible); ingo@4232: } ingo@4232: ingo@4232: protected void doHistoricalDischargeDifferenceOutQ(FLYSArtifact artifact, ingo@4232: Object data, String desc, Document theme, boolean visible) { ingo@2311: logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); ingo@2311: ingo@2311: HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; ingo@2311: ingo@4232: TimeSeriesCollection tsc = newTimeSeriesCollection(wqt.getTimeranges(), ingo@4232: wqt.getDiffs(), theme, desc); ingo@2240: ingo@4232: addAxisDataset(tsc, YAXIS.Q.idx, visible); ingo@2240: } ingo@2240: ingo@4232: protected void doHistoricalDischargeDifferenceOutW(FLYSArtifact artifact, ingo@4232: Object data, String desc, Document theme, boolean visible) { ingo@4232: logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); ingo@4232: ingo@4232: HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; ingo@4232: ingo@4232: TimeSeriesCollection tsc = newTimeSeriesCollection(wqt.getTimeranges(), ingo@4232: 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: */ ingo@2240: protected TimeSeriesCollection newTimeSeriesCollection( ingo@4232: Timerange[] timeranges, double[] values, Document theme, String desc) { ingo@2240: logger.debug("Create new TimeSeriesCollection for: " + desc); ingo@2240: ingo@2240: TimeSeriesCollection tsc = new TimeSeriesCollection(); ingo@4232: TimeSeries series = new StyledTimeSeries(desc, theme); ingo@2240: ingo@2311: for (int i = 0, n = timeranges.length; i < n; i++) { ingo@2311: RegularTimePeriod[] rtp = newRegularTimePeriod(timeranges[i]); ingo@2240: ingo@2240: try { ingo@2311: if (Double.isNaN(values[i])) { ingo@2243: logger.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: ingo@2243: if (logger.isDebugEnabled()) { ingo@2243: logger.debug("added Item to TimeSeries:"); ingo@2243: logger.debug(" TimePeriod: " + rtp[0] + " - " + rtp[1]); ingo@2311: logger.debug(" Value: " + values[i]); ingo@2243: } ingo@2240: } ingo@2240: catch (SeriesException se) { ingo@2240: logger.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: /** ingo@2240: * Creates an array that consists of two Minute periods [start, end]. teichmann@4736: * ingo@4232: * @param timerange ingo@4232: * Supports start and end time. teichmann@4736: * ingo@2240: * @return an array with two Minute periods [start, end]. ingo@2240: */ ingo@2240: protected RegularTimePeriod[] newRegularTimePeriod(Timerange timerange) { ingo@2240: Date start = new Date(timerange.getStart()); ingo@4232: Date end = new Date(timerange.getEnd() - 1000 * 60 * 60 * 24); ingo@2240: ingo@4232: return new RegularTimePeriod[] { new Day(start), new Day(end) }; ingo@2215: } ingo@2215: } ingo@2215: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :