ingo@2215: package de.intevation.flys.exports;
ingo@2215:
ingo@2215: import java.awt.Font;
ingo@2240: import java.util.Date;
ingo@2215:
ingo@2215: import org.w3c.dom.Document;
ingo@2215:
ingo@2215: import org.apache.log4j.Logger;
ingo@2215:
ingo@2215: import org.jfree.chart.JFreeChart;
ingo@2215: import org.jfree.chart.axis.NumberAxis;
ingo@2249: import org.jfree.chart.title.TextTitle;
ingo@2215:
ingo@2240: import org.jfree.data.general.SeriesException;
ingo@2243: import org.jfree.data.time.Day;
ingo@2240: import org.jfree.data.time.RegularTimePeriod;
ingo@2240: import org.jfree.data.time.TimeSeries;
ingo@2240: import org.jfree.data.time.TimeSeriesCollection;
ingo@2240:
ingo@2215: import de.intevation.artifactdatabase.state.ArtifactAndFacet;
ingo@2215:
ingo@2215: import de.intevation.flys.artifacts.FLYSArtifact;
ingo@2215: import de.intevation.flys.artifacts.model.FacetTypes;
ingo@2311: import de.intevation.flys.artifacts.model.HistoricalWQTimerange;
ingo@2240: import de.intevation.flys.artifacts.model.Timerange;
ingo@2240: import de.intevation.flys.artifacts.model.WQTimerange;
ingo@2321: import de.intevation.flys.jfree.StyledTimeSeries;
ingo@2249: import de.intevation.flys.utils.FLYSUtils;
ingo@2215:
ingo@2215:
ingo@2215: /**
ingo@2215: * @author Ingo Weinzierl
ingo@2215: */
ingo@2215: public class HistoricalDischargeCurveGenerator
ingo@2233: extends TimeseriesChartGenerator
ingo@2215: implements FacetTypes
ingo@2215: {
ingo@2215: private static Logger logger =
ingo@2215: Logger.getLogger(HistoricalDischargeCurveGenerator.class);
ingo@2215:
ingo@2215:
ingo@2249: public static final String I18N_CHART_TITLE =
ingo@2249: "chart.historical.discharge.title";
ingo@2249:
ingo@2249: public static final String I18N_CHART_SUBTITLE =
ingo@2249: "chart.historical.discharge.subtitle";
ingo@2249:
ingo@2249: public static final String I18N_XAXIS_LABEL =
ingo@2249: "chart.historical.discharge.xaxis.label";
ingo@2249:
ingo@2249: public static final String I18N_YAXIS_LABEL =
ingo@2249: "chart.historical.discharge.yaxis.label";
ingo@2249:
ingo@2249: public static final String I18N_YAXIS_SECOND_LABEL =
ingo@2249: "chart.historical.discharge.yaxis.second.label";
ingo@2249:
ingo@2249:
ingo@2215: public static enum YAXIS {
ingo@2215: Q(0);
ingo@2215: protected int idx;
ingo@2215: private YAXIS(int c) {
ingo@2215: idx = c;
ingo@2215: }
ingo@2215: }
ingo@2215:
ingo@2215:
ingo@2215: @Override
ingo@2215: protected YAxisWalker getYAxisWalker() {
ingo@2215: return new YAxisWalker() {
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:
ingo@2215: @Override
ingo@2215: protected String getDefaultChartTitle() {
ingo@2249: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
ingo@2249: }
ingo@2249:
ingo@2249:
ingo@2249: @Override
ingo@2249: protected String getDefaultChartSubtitle() {
ingo@2249: String[] args = new String[] {
ingo@2249: FLYSUtils.getReferenceGaugeName((FLYSArtifact) master)
ingo@2249: };
ingo@2249:
ingo@2249: return msg(I18N_CHART_SUBTITLE, "", args);
ingo@2215: }
ingo@2215:
ingo@2215:
ingo@2215: /**
ingo@2215: * Empty (suppress subtitle).
ingo@2215: */
ingo@2215: @Override
ingo@2215: protected void addSubtitles(JFreeChart chart) {
ingo@2249: String subtitle = getChartSubtitle();
ingo@2249:
ingo@2249: if (subtitle != null && subtitle.length() > 0) {
ingo@2249: chart.addSubtitle(new TextTitle(subtitle));
ingo@2249: }
ingo@2215: }
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@2215:
ingo@2215: /**
ingo@2215: * Creates a new Y-Axis.
ingo@2215: *
ingo@2215: * @param index the index of the Y axis.
ingo@2215: *
ingo@2215: * @return an new NumberAxis with label from getYAxisLabel().
ingo@2215: */
ingo@2215: @Override
ingo@2215: protected NumberAxis createYAxis(int index) {
ingo@2215: Font labelFont = new Font("Tahoma", Font.BOLD, 14);
ingo@2215: String label = "default";
ingo@2215:
ingo@2215: if (index == YAXIS.Q.idx) {
ingo@2215: label = getYAxisLabel(0);
ingo@2215: }
ingo@2215:
ingo@2215: NumberAxis axis = createNumberAxis(index, label);
ingo@2215: axis.setLabelFont(labelFont);
ingo@2215: axis.setAutoRangeIncludesZero(false);
ingo@2215:
ingo@2215: return axis;
ingo@2215: }
ingo@2215:
ingo@2215:
ingo@2215: public void doOut(
ingo@2215: ArtifactAndFacet artifactFacet,
ingo@2215: Document theme,
ingo@2215: boolean visible
ingo@2215: ) {
ingo@2215: String name = artifactFacet.getFacetName();
ingo@2215: logger.debug("HistoricalDischargeCurveGenerator.doOut: " + name);
ingo@2325: logger.debug("Theme description is: " + artifactFacet.getFacetDescription());
ingo@2215:
ingo@2215:
ingo@2215: if (name.equals(HISTORICAL_DISCHARGE_Q)) {
ingo@2215: doHistoricalDischargeOut(
ingo@2215: (FLYSArtifact) artifactFacet.getArtifact(),
ingo@2215: artifactFacet.getData(context),
ingo@2215: artifactFacet.getFacetDescription(),
ingo@2215: theme,
ingo@2215: visible);
ingo@2215: }
ingo@2311: else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) {
ingo@2311: doHistoricalDischargeDifferenceOut(
ingo@2311: (FLYSArtifact) artifactFacet.getArtifact(),
ingo@2311: artifactFacet.getData(context),
ingo@2311: artifactFacet.getFacetDescription(),
ingo@2311: theme,
ingo@2311: visible);
ingo@2311: }
ingo@2311: // TODO ADD THE CASE FOR DISPLAYING W VALUES
ingo@2215: else {
ingo@2215: logger.warn("doOut(): unknown facet name: " + name);
ingo@2215: return;
ingo@2215: }
ingo@2215: }
ingo@2215:
ingo@2215:
ingo@2215: protected void doHistoricalDischargeOut(
ingo@2215: FLYSArtifact artifact,
ingo@2215: Object data,
ingo@2215: String desc,
ingo@2215: Document theme,
ingo@2215: boolean visible)
ingo@2215: {
ingo@2215: logger.debug("doHistoricalDischargeOut(): description = " + desc);
ingo@2240:
ingo@2240: WQTimerange wqt = (WQTimerange) data;
ingo@2240:
ingo@2311: TimeSeriesCollection tsc = newTimeSeriesCollection(
ingo@2311: wqt.getTimeranges(),
ingo@2311: wqt.getQs(),
ingo@2321: theme,
ingo@2311: desc);
ingo@2311:
ingo@2311: addAxisDataset(tsc, 0, visible);
ingo@2311: }
ingo@2311:
ingo@2311:
ingo@2311: protected void doHistoricalDischargeDifferenceOut(
ingo@2311: FLYSArtifact artifact,
ingo@2311: Object data,
ingo@2311: String desc,
ingo@2311: Document theme,
ingo@2311: boolean visible
ingo@2311: ) {
ingo@2311: logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc);
ingo@2311:
ingo@2311: HistoricalWQTimerange wqt = (HistoricalWQTimerange) data;
ingo@2311:
ingo@2311: TimeSeriesCollection tsc = newTimeSeriesCollection(
ingo@2311: wqt.getTimeranges(),
ingo@2311: wqt.getDiffs(),
ingo@2321: theme,
ingo@2311: desc);
ingo@2240:
ingo@2240: addAxisDataset(tsc, 0, visible);
ingo@2240: }
ingo@2240:
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@2311: Timerange[] timeranges,
ingo@2311: double[] values,
ingo@2321: Document theme,
ingo@2240: String desc
ingo@2240: ) {
ingo@2240: logger.debug("Create new TimeSeriesCollection for: " + desc);
ingo@2240:
ingo@2240: TimeSeriesCollection tsc = new TimeSeriesCollection();
ingo@2321: 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: /**
ingo@2240: * Creates an array that consists of two Minute periods [start, end].
ingo@2240: *
ingo@2240: * @param timerange Supports start and end time.
ingo@2240: *
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@2243: Date end = new Date(timerange.getEnd() - 1000 * 60 * 60 * 24);
ingo@2240:
ingo@2240: return new RegularTimePeriod[] {
ingo@2243: new Day(start),
ingo@2243: new Day(end)
ingo@2240: };
ingo@2215: }
ingo@2215: }
ingo@2215: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :