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 :