ingo@1115: /*
ingo@1115: * Copyright (c) 2010 by Intevation GmbH
ingo@1115: *
ingo@1115: * This program is free software under the LGPL (>=v2.1)
ingo@1115: * Read the file LGPL.txt coming with the software for details
ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist.
ingo@1115: */
ingo@1115:
ingo@298: package de.intevation.gnv.chart;
ingo@298:
sascha@514: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
sascha@514:
sascha@514: import de.intevation.gnv.geobackend.base.Result;
sascha@514:
sascha@514: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
sascha@514:
sascha@514: import de.intevation.gnv.timeseries.gap.TimeGap;
sascha@514:
ingo@526: import java.text.DateFormat;
ingo@526: import java.text.SimpleDateFormat;
ingo@526:
ingo@298: import java.util.Collection;
ingo@329: import java.util.Date;
ingo@334: import java.util.HashMap;
ingo@298: import java.util.Iterator;
ingo@298: import java.util.Locale;
ingo@505: import java.util.TimeZone;
ingo@298:
ingo@298: import org.apache.log4j.Logger;
ingo@298:
sascha@514: import org.jfree.chart.ChartFactory;
ingo@298: import org.jfree.chart.ChartTheme;
sascha@514:
ingo@315: import org.jfree.chart.axis.Axis;
ingo@315: import org.jfree.chart.axis.DateAxis;
ingo@526: import org.jfree.chart.axis.DateTickUnit;
ingo@526: import org.jfree.chart.axis.DateTickUnitType;
sascha@779: import org.jfree.chart.axis.TickUnitSource;
ingo@526: import org.jfree.chart.axis.TickUnits;
ingo@526: import org.jfree.chart.axis.ValueAxis;
sascha@514:
ingo@298: import org.jfree.chart.plot.PlotOrientation;
sascha@514: import org.jfree.chart.plot.XYPlot;
sascha@514:
ingo@298: import org.jfree.data.general.Series;
sascha@514:
sascha@514: import org.jfree.data.time.Minute;
ingo@298: import org.jfree.data.time.TimeSeries;
ingo@298: import org.jfree.data.time.TimeSeriesCollection;
ingo@298:
ingo@298: /**
ingo@767: * This class is used to create timeseries charts. The domain axis contains
ingo@767: * multiple date/time objects.
ingo@767: *
ingo@767: * @author Ingo Weinzierl
ingo@298: */
ingo@298: public class TimeSeriesChart
ingo@298: extends AbstractXYLineChart
ingo@298: {
ingo@298:
ingo@767: /**
ingo@767: * Constant format which can be useful to format date items. Value is
ingo@767: * {@value}.
ingo@767: */
ingo@350: public static final String DEFAULT_DATE_FORMAT = "dd-MMM-yyyy";
ingo@315:
ingo@767: /**
ingo@767: * Constant field used if no gap detection should be done here. This field
ingo@767: * is used in @see #getTimeGapValue. Value is {@value}.
ingo@767: */
ingo@642: public static final long NO_TIME_GAP = Long.MAX_VALUE - 1000;
ingo@767:
ingo@767: /**
ingo@767: * Percentage used for gap detection. Its value is {@value}.
ingo@767: */
ingo@831: public static int GAP_SIZE = 5; // in percent
ingo@329:
ingo@767: /**
ingo@767: * Logger used for logging with log4j.
ingo@767: */
ingo@298: private static Logger log = Logger.getLogger(TimeSeriesChart.class);
ingo@298:
ingo@831: static {
sascha@835: /* The percentage defining the width of a gap should be configured in
ingo@831: * conf.xml instead of being configured in a system property */
ingo@831: GAP_SIZE = Integer.getInteger("chart.gap.percentage", GAP_SIZE);
ingo@831: }
ingo@831:
ingo@298:
ingo@767: /**
ingo@767: * Constructor used to create TimeSeries
charts.
ingo@767: *
ingo@767: * @param labels Labels used to be displayed in title, subtitle and so on.
ingo@767: * @param theme ChartTheme used to adjust the rendering of this chart.
ingo@767: * @param parameters Collection containing a bunch of parameters.
ingo@767: * @param measurements Collection containing a bunch of measurements.
ingo@767: * @param dates Collection containing a bunch of date objects.
ingo@767: * @param result Collection containing a bunch of Result
ingo@767: * objects which contain the actual data items to be displayed.
ingo@767: * @param timeGaps Collection with timegap definitions.
ingo@767: * @param locale Locale used to specify the format of labels, numbers, ...
ingo@767: * @param linesVisible Render lines between data points if true, otherwise
ingo@767: * not.
ingo@767: * @param shapesVisible Render vertices as points if true, otherwise not.
ingo@767: */
ingo@298: public TimeSeriesChart(
ingo@298: ChartLabels labels,
ingo@298: ChartTheme theme,
ingo@298: Collection parameters,
ingo@298: Collection measurements,
ingo@310: Collection dates,
ingo@298: Collection result,
ingo@310: Collection timeGaps,
ingo@327: Locale locale,
ingo@327: boolean linesVisible,
ingo@327: boolean shapesVisible
ingo@298: ) {
ingo@298: this.labels = labels;
ingo@298: this.theme = theme;
ingo@298: this.parameters = parameters;
ingo@298: this.measurements = measurements;
ingo@310: this.dates = dates;
ingo@298: this.resultSet = result;
ingo@310: this.timeGaps = timeGaps;
ingo@298: this.locale = locale;
ingo@298: this.PLOT_ORIENTATION = PlotOrientation.VERTICAL;
ingo@327: this.linesVisible = linesVisible;
ingo@327: this.shapesVisible = shapesVisible;
ingo@334: this.datasets = new HashMap();
ingo@364: this.ranges = new HashMap();
ingo@298: }
ingo@298:
ingo@298:
ingo@767: /**
ingo@767: * see de.intevation.gnv.chart.AbstractXYLineChart#initChart()
ingo@767: */
ingo@788: @Override
ingo@333: protected void initChart() {
ingo@312: chart = ChartFactory.createTimeSeriesChart(
ingo@312: labels.getTitle(),
ingo@312: labels.getDomainAxisLabel(),
ingo@312: null,
ingo@312: null,
ingo@312: true,
ingo@312: false,
ingo@312: false
ingo@312: );
ingo@505:
ingo@505: XYPlot plot = (XYPlot) chart.getPlot();
ingo@505: plot.setDomainAxis(0, new DateAxis(
ingo@505: labels.getDomainAxisLabel(), TimeZone.getDefault(), locale));
ingo@312: }
ingo@312:
ingo@312:
ingo@767: /**
ingo@767: * @see de.intevation.gnv.chart.AbstractXYLineChart#initData()
ingo@767: */
ingo@298: protected void initData() {
ingo@298: log.debug("init data for timeseries chart");
ingo@298:
ingo@298: String breakPoint1 = null;
ingo@298: String breakPoint2 = null;
ingo@298: String breakPoint3 = null;
ingo@298:
ingo@298: Iterator iter = resultSet.iterator();
ingo@298: Result row = null;
ingo@298: String seriesName = null;
ingo@364: String parameter = null;
ingo@298: TimeSeries series = null;
ingo@298:
ingo@329: int idx = 0;
ingo@329: int startPos = 0;
ingo@329: int endPos = 0;
ingo@329: Date startDate = null;
ingo@329: Date endDate = null;
ingo@329:
ingo@329: Result[] results =
ingo@329: (Result[]) resultSet.toArray(new Result[resultSet.size()]);
ingo@298:
ingo@298: while (iter.hasNext()) {
ingo@298: row = (Result) iter.next();
ingo@298:
ingo@298: // add current data to plot and prepare for next one
ingo@298: if (!row.getString("GROUP1").equals(breakPoint1) ||
ingo@298: !row.getString("GROUP2").equals(breakPoint2) ||
ingo@298: !row.getString("GROUP3").equals(breakPoint3)
ingo@298: ) {
ingo@298: log.debug("prepare data/plot for next dataset");
ingo@298:
ingo@298: if(series != null) {
ingo@329: // add gaps before adding series to chart
ingo@329: startDate = results[startPos].getDate("XORDINATE");
ingo@329: endDate = results[endPos-1].getDate("XORDINATE");
ingo@329: addGaps(results,series,startDate,endDate,startPos,endPos);
ingo@364: addSeries(series, parameter, idx);
ingo@329:
ingo@329: startPos = endPos + 1;
ingo@298: }
ingo@298:
ingo@298: // prepare variables for next plot
ingo@298: breakPoint1 = row.getString("GROUP1");
ingo@298: breakPoint2 = row.getString("GROUP2");
ingo@298: breakPoint3 = row.getString("GROUP3");
ingo@298:
ingo@298: seriesName = createSeriesName(
ingo@298: breakPoint1,
ingo@298: breakPoint2,
ingo@298: breakPoint3
ingo@298: );
ingo@364: parameter = findParameter(seriesName);
ingo@298:
ingo@298: log.debug("next dataset is '" + seriesName + "'");
ingo@298: series = new TimeSeries(seriesName, Minute.class);
ingo@298: }
ingo@298:
ingo@298: addValue(row, series);
ingo@656: storeMaxRange(ranges, row.getDouble("YORDINATE"), parameter);
ingo@329: endPos++;
ingo@298: }
ingo@298:
ingo@496: if (startPos < results.length && endPos-1 < results.length) {
ingo@496: // add the last dataset if existing to plot and prepare its axis
ingo@496: startDate = results[startPos].getDate("XORDINATE");
ingo@496: endDate = results[endPos-1].getDate("XORDINATE");
ingo@496: addGaps(results, series, startDate, endDate, startPos, endPos);
ingo@496: addSeries(series, parameter, idx);
ingo@496: }
ingo@310:
ingo@334: addDatasets();
ingo@298: }
ingo@298:
ingo@298:
ingo@767: /**
ingo@767: * @see de.intevation.gnv.chart.AbstractXYLineChart#addValue(Result, Series)
ingo@767: */
ingo@298: protected void addValue(Result row, Series series) {
ingo@298: ((TimeSeries) series).addOrUpdate(
ingo@298: new Minute(row.getDate("XORDINATE")),
ingo@298: row.getDouble("YORDINATE")
ingo@298: );
ingo@298: }
ingo@298:
ingo@298:
ingo@767: /**
ingo@788: * @param parameter
ingo@767: * @see de.intevation.gnv.chart.AbstractXYLineChart#addSeries(Series,
ingo@767: * String, int)
ingo@767: */
ingo@364: protected void addSeries(Series series, String parameter, int idx) {
ingo@364: log.debug("add series (" + parameter + ")to timeseries chart");
ingo@298:
ingo@298: if (series == null) {
ingo@298: log.warn("no data to add");
ingo@298: return;
ingo@298: }
ingo@298:
ingo@334: TimeSeriesCollection tsc = null;
ingo@334:
ingo@334: if (datasets.containsKey(parameter))
ingo@334: tsc = (TimeSeriesCollection) datasets.get(parameter);
ingo@334: else
ingo@334: tsc = new TimeSeriesCollection();
ingo@334:
ingo@334: tsc.addSeries((TimeSeries) series);
ingo@334: datasets.put(parameter, tsc);
ingo@334: }
ingo@334:
ingo@334:
ingo@767: /**
ingo@767: * Method to add processed datasets to plot. Each dataset is adjusted using
ingo@767: * prepareAxis
and adjustRenderer
methods.
ingo@767: */
ingo@334: protected void addDatasets() {
ingo@334: Iterator iter = parameters.iterator();
ingo@334: XYPlot plot = chart.getXYPlot();
ingo@334: int idx = 0;
ingo@334:
ingo@334: TimeSeriesCollection tsc = null;
ingo@334: KeyValueDescibeData data = null;
ingo@334: String key = null;
ingo@334: while (iter.hasNext()) {
ingo@334: data = (KeyValueDescibeData) iter.next();
ingo@334: key = data.getValue();
ingo@334:
ingo@334: if (datasets.containsKey(key)) {
ingo@334: tsc = (TimeSeriesCollection)datasets.get(key);
ingo@334: plot.setDataset(idx, tsc );
ingo@334: log.debug("Added " + key + " parameter to plot.");
ingo@334: prepareAxis(key, idx);
ingo@334: adjustRenderer(
ingo@334: idx++,
ingo@334: tsc.getSeriesCount(),
ingo@334: linesVisible,
ingo@334: shapesVisible
ingo@334: );
ingo@334: }
ingo@334: }
ingo@298: }
ingo@298:
ingo@298:
ingo@767: /**
ingo@788: * @param locale
ingo@767: * @see de.intevation.gnv.chart.AbstractXYLineChart#localizeDomainAxis(Axis,
ingo@767: * Locale)
ingo@767: */
ingo@315: protected void localizeDomainAxis(Axis axis, Locale locale) {
ingo@526: ((ValueAxis)axis).setStandardTickUnits(createStandardDateTickUnits(
ingo@526: TimeZone.getDefault(),
ingo@526: locale));
ingo@526: }
ingo@526:
ingo@526:
ingo@767: /**
ingo@788: * @param zone
ingo@788: * @param locale
ingo@788: * @return TickUnitSource
ingo@767: * @see org.jfree.chart.axis.DateAxis#createStandardDateTickUnits(TimeZone,
ingo@767: * Locale)
ingo@767: */
ingo@526: public static TickUnitSource createStandardDateTickUnits(
ingo@526: TimeZone zone,
ingo@526: Locale locale)
ingo@526: {
sascha@778: /*
ingo@526: * This method have been copied from JFreeChart's DateAxis class.
ingo@526: * DateFormat objects are hard coded in DateAxis and cannot be adjusted.
ingo@526: */
ingo@526: if (zone == null) {
ingo@526: throw new IllegalArgumentException("Null 'zone' argument.");
ingo@526: }
ingo@526: if (locale == null) {
ingo@526: throw new IllegalArgumentException("Null 'locale' argument.");
ingo@526: }
ingo@526: TickUnits units = new TickUnits();
ingo@526:
ingo@526: // date formatters
ingo@526: DateFormat f1 = new SimpleDateFormat("HH:mm:ss.SSS", locale);
ingo@526: DateFormat f2 = new SimpleDateFormat("HH:mm:ss", locale);
ingo@526: DateFormat f3 = new SimpleDateFormat("HH:mm", locale);
ingo@526: DateFormat f4 = new SimpleDateFormat("d-MMM, HH:mm", locale);
ingo@526: DateFormat f5 = new SimpleDateFormat("d-MMM yyyy", locale);
ingo@526: DateFormat f6 = new SimpleDateFormat("MMM-yyyy", locale);
ingo@526: DateFormat f7 = new SimpleDateFormat("yyyy", locale);
ingo@526:
ingo@526: f1.setTimeZone(zone);
ingo@526: f2.setTimeZone(zone);
ingo@526: f3.setTimeZone(zone);
ingo@526: f4.setTimeZone(zone);
ingo@526: f5.setTimeZone(zone);
ingo@526: f6.setTimeZone(zone);
ingo@526: f7.setTimeZone(zone);
ingo@526:
ingo@526: // milliseconds
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 1, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 5,
ingo@526: DateTickUnitType.MILLISECOND, 1, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 10,
ingo@526: DateTickUnitType.MILLISECOND, 1, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 25,
ingo@526: DateTickUnitType.MILLISECOND, 5, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 50,
ingo@526: DateTickUnitType.MILLISECOND, 10, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 100,
ingo@526: DateTickUnitType.MILLISECOND, 10, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 250,
ingo@526: DateTickUnitType.MILLISECOND, 10, f1));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 500,
ingo@526: DateTickUnitType.MILLISECOND, 50, f1));
ingo@526:
ingo@526: // seconds
ingo@526: units.add(new DateTickUnit(DateTickUnitType.SECOND, 1,
ingo@526: DateTickUnitType.MILLISECOND, 50, f2));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.SECOND, 5,
ingo@526: DateTickUnitType.SECOND, 1, f2));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.SECOND, 10,
ingo@526: DateTickUnitType.SECOND, 1, f2));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.SECOND, 30,
ingo@526: DateTickUnitType.SECOND, 5, f2));
ingo@526:
ingo@526: // minutes
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 1,
ingo@526: DateTickUnitType.SECOND, 5, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 2,
ingo@526: DateTickUnitType.SECOND, 10, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 5,
ingo@526: DateTickUnitType.MINUTE, 1, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 10,
ingo@526: DateTickUnitType.MINUTE, 1, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 15,
ingo@526: DateTickUnitType.MINUTE, 5, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 20,
ingo@526: DateTickUnitType.MINUTE, 5, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MINUTE, 30,
ingo@526: DateTickUnitType.MINUTE, 5, f3));
ingo@526:
ingo@526: // hours
ingo@526: units.add(new DateTickUnit(DateTickUnitType.HOUR, 1,
ingo@526: DateTickUnitType.MINUTE, 5, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.HOUR, 2,
ingo@526: DateTickUnitType.MINUTE, 10, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.HOUR, 4,
ingo@526: DateTickUnitType.MINUTE, 30, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.HOUR, 6,
ingo@526: DateTickUnitType.HOUR, 1, f3));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.HOUR, 12,
ingo@526: DateTickUnitType.HOUR, 1, f4));
ingo@526:
ingo@526: // days
ingo@526: units.add(new DateTickUnit(DateTickUnitType.DAY, 1,
ingo@526: DateTickUnitType.HOUR, 1, f5));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.DAY, 2,
ingo@526: DateTickUnitType.HOUR, 1, f5));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.DAY, 7,
ingo@526: DateTickUnitType.DAY, 1, f5));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.DAY, 15,
ingo@526: DateTickUnitType.DAY, 1, f5));
ingo@526:
ingo@526: // months
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MONTH, 1,
ingo@526: DateTickUnitType.DAY, 1, f6));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MONTH, 2,
ingo@526: DateTickUnitType.DAY, 1, f6));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MONTH, 3,
ingo@526: DateTickUnitType.MONTH, 1, f6));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MONTH, 4,
ingo@526: DateTickUnitType.MONTH, 1, f6));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.MONTH, 6,
ingo@526: DateTickUnitType.MONTH, 1, f6));
ingo@526:
ingo@526: // years
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 1,
ingo@526: DateTickUnitType.MONTH, 1, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 2,
ingo@526: DateTickUnitType.MONTH, 3, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 5,
ingo@526: DateTickUnitType.YEAR, 1, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 10,
ingo@526: DateTickUnitType.YEAR, 1, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 25,
ingo@526: DateTickUnitType.YEAR, 5, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 50,
ingo@526: DateTickUnitType.YEAR, 10, f7));
ingo@526: units.add(new DateTickUnit(DateTickUnitType.YEAR, 100,
ingo@526: DateTickUnitType.YEAR, 20, f7));
ingo@526:
ingo@526: return units;
ingo@315: }
ingo@315:
ingo@315:
ingo@767: /**
ingo@767: * Method to get a message from resource bundle.
ingo@767: *
ingo@788: * @param locale Locale used to specify the resource bundle.
ingo@788: * @param key Key to specify the required message.
ingo@788: * @param def Default string if resource is not existing.
ingo@767: *
ingo@767: * @return Message
ingo@767: */
ingo@350: protected String getMessage(Locale locale, String key, String def) {
ingo@350: return RessourceFactory.getInstance().getRessource(locale, key, def);
ingo@350: }
ingo@350:
ingo@350:
ingo@767: /**
ingo@767: * @see de.intevation.gnv.chart.AbstractXYLineChart#createSeriesName(String,
ingo@767: * String, String)
ingo@767: */
ingo@298: protected String createSeriesName(
ingo@298: String breakPoint1,
ingo@298: String breakPoint2,
ingo@298: String breakPoint3
ingo@298: ) {
ingo@298: log.debug("create seriesname of timeseries chart");
ingo@298: return findValueTitle(parameters, breakPoint1) +
ingo@298: " " +
ingo@298: findValueTitle(measurements, breakPoint2) +
ingo@298: "m";
ingo@298: }
ingo@329:
ingo@329:
ingo@767: /**
sascha@778: * Method to add gaps between two data points. The max valid space between
ingo@767: * two data points is calculated by calculateGapSize
.
ingo@767: *
ingo@767: * @param results All data points in this dataset.
ingo@767: * @param series Series to be processed.
ingo@767: * @param startDate Date item where the scan for gaps should begin.
ingo@767: * @param endDate Date item where the scan should end.
ingo@767: * @param startPos Start position of this series in results
.
ingo@767: * @param endPos End position of a series in results
ingo@767: */
ingo@329: protected void addGaps(
ingo@329: Result[] results,
ingo@329: Series series,
ingo@329: Date startDate,
ingo@329: Date endDate,
ingo@329: int startPos,
ingo@329: int endPos
ingo@329: ) {
ingo@329: int gapID = results[startPos].getInteger("GAPID");
ingo@329: long maxDiff = calculateGapSize(
ingo@329: startDate, endDate, startPos, endPos, gapID
ingo@329: );
ingo@329:
ingo@642: if (log.isDebugEnabled()) {
ingo@642: log.debug("*****************************************************");
ingo@642: log.debug("Values of gap detection.");
ingo@642: log.debug("Start date: " + startDate.toString());
ingo@642: log.debug("End date: " + endDate.toString());
ingo@642: long diff = endDate.getTime() - startDate.getTime();
ingo@642: log.debug("Time difference (in ms): " + diff);
ingo@642: log.debug("Time difference (in h): " + (diff/(1000*60*60)));
ingo@642: log.debug("Configured gap size (in %): " + GAP_SIZE);
ingo@642: log.debug("Calculated gap size (in ms): " + maxDiff);
ingo@642: log.debug("Calculated gap size (in h): " + (maxDiff/(1000*60*60)));
ingo@642: log.debug("*****************************************************");
ingo@642: }
ingo@642:
ingo@329: Date last = startDate;
ingo@329: for (int i = startPos+1; i < endPos; i++) {
ingo@329: Result res = results[i];
ingo@329: Date now = res.getDate("XORDINATE");
ingo@329:
ingo@329: if ((now.getTime() - last.getTime()) > maxDiff) {
ingo@329: // add gap, add 1 minute to last date and add null value
ingo@329: log.info(
ingo@329: "Gap between " +
ingo@329: last.toString() + " and " + now.toString()
ingo@329: );
ingo@329: last.setTime(last.getTime() + 60000);
ingo@329: ((TimeSeries) series).addOrUpdate(new Minute(last), null);
ingo@329: }
ingo@329:
ingo@329: last = now;
ingo@329: }
ingo@329: }
ingo@329:
ingo@329:
ingo@767: /**
ingo@767: * Method to calculate the max space between two data points.
ingo@767: *
ingo@767: * @param start First date
ingo@767: * @param end Last date
ingo@767: * @param startPos Start position of the current series in the collection
ingo@767: * containing the bunch of series.
ingo@767: * @param endPos End position of the current series in the collection
ingo@767: * containing the bunch of series.
ingo@767: * @param gapID Gap id used to specify the time intervals.
ingo@767: *
ingo@767: * @return Min size of a gap.
ingo@767: */
ingo@329: protected long calculateGapSize(
ingo@329: Date start,
ingo@329: Date end,
ingo@329: int startPos,
ingo@329: int endPos,
ingo@329: int gapID
ingo@329: ){
ingo@642: long maxGap = (end.getTime() - start.getTime()) / 100 * GAP_SIZE;
ingo@329: long interval = getTimeGapValue(start, end, startPos, endPos, gapID);
ingo@329:
ingo@329: if (maxGap < interval)
ingo@329: maxGap = interval + 10;
ingo@329:
ingo@329: return maxGap;
ingo@329: }
ingo@329:
ingo@329:
ingo@767: /**
ingo@767: * Determine the interval size between two data points.
ingo@767: *
ingo@767: * @param dStart Start date
ingo@767: * @param dEnd End date
sascha@778: * @param pStart Index of start point in series used to specify the total
ingo@767: * amount of date items.
ingo@767: * @param pEnd Index of end point in series used to specify the total amount
ingo@767: * of date items.
ingo@767: * @param gapID Gap id used to determine gaps configured in a xml document.
ingo@767: *
ingo@767: * @return Interval size between two data points.
ingo@767: */
ingo@329: protected long getTimeGapValue(
ingo@329: Date dStart,
ingo@329: Date dEnd,
ingo@329: int pStart,
ingo@329: int pEnd,
ingo@329: int gapID
ingo@329: ){
ingo@329: long gap = 0;
ingo@329:
ingo@329: if (gapID < 0 || gapID >= 99) {
ingo@329:
ingo@329: if (gapID == -1) {
ingo@329: // no gaps in meshes
ingo@329: gap = NO_TIME_GAP;
ingo@329: }
ingo@329: else if (pEnd-pStart < 60) {
ingo@329: gap = (3/(pEnd-pStart)) * (dEnd.getTime() - dStart.getTime());
ingo@329: }
ingo@329: }
ingo@329: else{
ingo@329: Iterator it = timeGaps.iterator();
ingo@329:
ingo@329: while (it.hasNext()) {
ingo@329: TimeGap tempTimeGap = (TimeGap) it.next();
ingo@329:
ingo@329: if (tempTimeGap.getKey() == gapID){
ingo@329: String unit = tempTimeGap.getUnit();
ingo@329: int gapValue = tempTimeGap.getValue();
ingo@329:
ingo@329: if (unit.equals(TimeGap.TIME_UNIT_MINUTE)) {
ingo@329: gap = gapValue * TimeGap.MINUTE_IN_MILLIS;
ingo@329: }
ingo@329: else if (unit.equals(TimeGap.TIME_UNIT_HOUR)) {
ingo@329: gap = gapValue * TimeGap.HOUR_IN_MILLIS;
ingo@329: }
ingo@329: else if (unit.equals(TimeGap.TIME_UNIT_DAY)) {
ingo@329: gap = gapValue * TimeGap.DAY_IN_MILLIS;
ingo@329: }
ingo@329: else if (unit.equals(TimeGap.TIME_UNIT_WEEK)) {
ingo@329: gap = gapValue * TimeGap.WEEK_IN_MILLIS;
ingo@329: }
ingo@329: else if (unit.equals(TimeGap.TIME_UNIT_MONTH)) {
ingo@329: gap = gapValue * (TimeGap.DAY_IN_MILLIS *30);
ingo@329: }
ingo@329: else if (unit.equals(TimeGap.TIME_UNIT_YEAR)) {
ingo@329: gap = gapValue * (TimeGap.DAY_IN_MILLIS *365);
ingo@329: }
ingo@329: break;
ingo@329: }
ingo@329: }
ingo@329: }
ingo@329:
ingo@329: return gap;
ingo@329: }
ingo@298: }
ingo@315: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :