tim@335: package de.intevation.gnv.state.timeseries;
tim@335: 
sascha@480: import java.io.IOException;
tim@335: import java.io.OutputStream;
tim@335: import java.io.UnsupportedEncodingException;
ingo@839: 
ingo@839: import java.text.DateFormat;
ingo@851: import java.text.NumberFormat;
ingo@839: import java.text.ParseException;
ingo@839: 
tim@335: import java.util.ArrayList;
tim@335: import java.util.Collection;
ingo@839: import java.util.Date;
ingo@629: import java.util.HashMap;
tim@335: import java.util.Iterator;
tim@335: import java.util.List;
tim@335: import java.util.Locale;
ingo@629: import java.util.Map;
tim@335: import java.util.Vector;
tim@335: 
tim@335: import org.apache.log4j.Logger;
sascha@480: import org.jfree.chart.ChartTheme;
tim@335: import org.w3c.dom.Document;
tim@335: import org.w3c.dom.Element;
tim@335: import org.w3c.dom.Node;
tim@335: import org.w3c.dom.NodeList;
tim@335: 
tim@812: import au.com.bytecode.opencsv.CSVWriter;
tim@812: import de.intevation.artifactdatabase.Config;
tim@812: import de.intevation.artifactdatabase.XMLUtils;
tim@812: import de.intevation.artifacts.ArtifactNamespaceContext;
tim@812: import de.intevation.artifacts.CallContext;
tim@812: import de.intevation.artifacts.CallMeta;
tim@812: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
tim@812: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
tim@812: import de.intevation.gnv.chart.Chart;
tim@812: import de.intevation.gnv.chart.ChartLabels;
tim@812: import de.intevation.gnv.chart.DefaultHistogram;
tim@812: import de.intevation.gnv.chart.TimeSeriesChart;
tim@812: import de.intevation.gnv.chart.XMLChartTheme;
tim@812: import de.intevation.gnv.chart.exception.TechnicalChartException;
tim@812: import de.intevation.gnv.exports.ChartExportHelper;
tim@812: import de.intevation.gnv.exports.DefaultDataCollector;
tim@812: import de.intevation.gnv.exports.DefaultExport;
tim@812: import de.intevation.gnv.exports.DefaultProfile;
tim@812: import de.intevation.gnv.exports.Export;
tim@812: import de.intevation.gnv.exports.ODVExport;
tim@812: import de.intevation.gnv.exports.SimpleOdvDataCollector;
tim@812: import de.intevation.gnv.exports.Export.Profile;
tim@812: import de.intevation.gnv.geobackend.base.Result;
tim@812: import de.intevation.gnv.histogram.HistogramHelper;
tim@812: import de.intevation.gnv.state.InputData;
tim@812: import de.intevation.gnv.state.OutputStateBase;
ingo@838: import de.intevation.gnv.state.State;
tim@812: import de.intevation.gnv.state.describedata.DefaultKeyValueDescribeData;
tim@812: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
tim@812: import de.intevation.gnv.state.describedata.MinMaxDescribeData;
tim@812: import de.intevation.gnv.state.describedata.NamedArrayList;
tim@812: import de.intevation.gnv.state.describedata.NamedCollection;
tim@812: import de.intevation.gnv.state.exception.StateException;
tim@812: import de.intevation.gnv.statistics.Statistic;
tim@812: import de.intevation.gnv.statistics.StatisticSet;
tim@812: import de.intevation.gnv.statistics.Statistics;
tim@812: import de.intevation.gnv.statistics.TimeseriesStatistics;
tim@812: import de.intevation.gnv.statistics.exception.StatisticsException;
tim@812: import de.intevation.gnv.timeseries.gap.DefaultTimeGap;
tim@812: import de.intevation.gnv.timeseries.gap.TimeGap;
tim@812: import de.intevation.gnv.utils.ArtifactXMLUtilities;
tim@812: 
tim@335: /**
sascha@780:  * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
sascha@780:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
tim@335:  */
tim@335: public class TimeSeriesOutputState extends OutputStateBase {
tim@335: 
ingo@804:     /**
ingo@804:      * A boolean property to enable caching of charts after they have been
ingo@804:      * created. This property can be adjusted via system property 'cache.chart'.
ingo@804:      * 'true' of 'false' are valid options - defaults to 'false'.<br>
ingo@804:      * <b>NOTE:</b> If chart caching is enabled, charts aren't sensible to
ingo@804:      * changes in the parameterization anymore, after a first chart has been
ingo@804:      * created for an artifact.
ingo@804:      */
tim@335:     protected static final boolean CACHE_CHART =
tim@335:         Boolean.parseBoolean(System.getProperty("cache.chart", "false"));
tim@335: 
ingo@804:     /**
ingo@804:      * Supported image export formats.
ingo@804:      */
tim@335:     protected static final String[] IMG_EXPORT_FORMAT = {
tim@335:         "PNG", "JPEG", "GIF"
tim@335:     };
tim@335: 
tim@335:     /**
tim@335:      * The UID of this Class
tim@335:      */
tim@335:     private static final long serialVersionUID = 4178407570503098858L;
tim@335: 
tim@335:     /**
tim@335:      * the logger, used to log exceptions and additonaly information
tim@335:      */
tim@335:     private static Logger log = Logger
tim@335:             .getLogger(TimeSeriesOutputState.class);
tim@335: 
ingo@1040:     protected List<TimeGap> timeGapDefinitions = null;
tim@335: 
ingo@804:     /**
ingo@804:      * Key in resource bundle the x-axis title is stored.
ingo@804:      */
ingo@342:     protected String domainLable = "chart.timeseries.title.xaxis";
tim@335: 
tim@335:     protected String featureValuesName = "featureid";
tim@335:     protected String parameterValuesName = "parameterid";
tim@335:     protected String measuremenValueName = "measurementid";
tim@335:     protected String dateValueName = "dateid";
tim@812:     protected String timeIntervalValueName = "timeinterval";
ingo@368: 
ingo@804: 
ingo@804:     /**
ingo@804:      * Array used to specify the columns used in csv exports.
ingo@804:      */
ingo@368:     public static final String [] TIMESERIES_CSV_PROFILE_COLUMNS = {
tim@335:         "XORDINATE",
tim@335:         "YORDINATE",
tim@335:         "GROUP1",
tim@335:         "GROUP2",
tim@335:         "GROUP3"
tim@335:     };
ingo@368: 
ingo@368: 
ingo@804:     /**
ingo@804:      * Column labels used in csv exports.
ingo@804:      */
ingo@368:     public static final String [] TIMESERIES_TIMESERIES_CSV_COLUMN_LABEL = {
ingo@368:         "Date/Time",
ingo@368:         "Value",
ingo@368:         "ParameterID",
ingo@368:         "MeasurementID",
ingo@368:         "TimeseriesID"
ingo@368:     };
ingo@368: 
ingo@804: 
ingo@804:     /**
ingo@804:      * Array used to specify the column in csv exports on meshes.
ingo@804:      */
ingo@368:     public static final String [] TIMESERIES_MESH_CSV_COLUMN_LABEL = {
ingo@368:         "Date/Time",
ingo@368:         "Value",
ingo@368:         "ParameterID",
ingo@368:         "FeatureID",
ingo@368:         "MeshID"
ingo@368:     };
ingo@368: 
ingo@804: 
ingo@804:     /**
ingo@804:      * Array used to specify the columns in odv exports.
ingo@804:      */
tim@335:     public static final String [] TIMESERIES_ODV_PROFILE_NAMES = {
tim@335:           "CRUISE",
tim@335:           "STATION",
tim@335:           "TYPE",
tim@765:           "TIMEVALUE",
tim@335:           "SHAPE",
tim@335:           "BOTDEPTH",
tim@335:           "DEPTH",
tim@765:           "QF"
tim@335:     };
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Column labels used in odv exports.
ingo@804:      */
tim@335:     public static final String [] ODV_COLUMN_HEADER = {
tim@335:         "Cruise",
tim@335:         "Station",
tim@335:         "Type",
tim@765:         "yyyy-mm-dd hh:mm",
tim@765:         "Lon (°E)",
tim@765:         "Lat (°N)",
tim@335:         "Bot. Depth [m]",
tim@335:         "Depth [m]",
tim@765:         "QF"
tim@335:     };
tim@335: 
sascha@805: 
tim@335:     /**
tim@335:      * Profile for exporting data to odv
tim@335:      */
tim@335:     public static final Profile TIMESERIES_ODV_PROFILE =
tim@335:         new DefaultProfile(
tim@335:             ODV_COLUMN_HEADER,
tim@335:             '\t',
tim@335:             CSVWriter.NO_QUOTE_CHARACTER,
tim@335:             CSVWriter.NO_ESCAPE_CHARACTER,
tim@335:             "ODV",
tim@335:             "ISO-8859-1");
tim@335: 
ingo@839: 
tim@335:     /**
tim@335:      * Constructor
tim@335:      */
tim@335:     public TimeSeriesOutputState() {
tim@335:         super();
tim@335:     }
tim@335: 
ingo@536: 
ingo@804:     /**
ingo@804:      * Calls <code>getChartResult</code> which puts the data used for chart
ingo@804:      * creation into cache. This redruces waiting periods after selecting an
ingo@804:      * output type.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param context The CallContext object.
ingo@804:      * @throws StateException if an error occured while fetching the data used
ingo@804:      * for chart creation.
ingo@804:      */
ingo@536:     @Override
ingo@536:     public void initialize(String uuid, CallContext context)
ingo@536:     throws StateException
ingo@536:     {
ingo@536:         getChartResult(uuid, context);
ingo@536:     }
ingo@536: 
ingo@536: 
tim@335:     /**
ingo@804:      * This out target has following modes:<br>
ingo@804:      * <ol>
ingo@804:      *  <li>chart: Creates a chart displaying the data corresponding to the
ingo@804:      * current parameterization. A chart has following export modes:<br>
ingo@804:      *      <ol>
ingo@804:      *          <li>img: Image representation of a chart.</li>
ingo@804:      *          <li>pdf: PDF representation of a chart.</li>
ingo@804:      *          <li>svg: SVG representation of a chart.</li>
ingo@804:      *      </ol>
ingo@804:      * All selected parameters are drawn into a single chart.<br>
ingo@804:      *  </li>
ingo@804:      *  <li>histogram: Creates a histogram displaying the data corresponding to
ingo@804:      * the current parameterization. A histogram has following export modes:<br>
ingo@804:      *      <ol>
ingo@804:      *          <li>img: Image representation of a histogram.</li>
ingo@804:      *          <li>pdf: PDF representation of a histogram.</li>
ingo@804:      *          <li>svg: SVG representation of a histogram.</li>
ingo@804:      *      </ol>
ingo@804:      * A single histogram is created for each selected parameter.<br>
ingo@804:      *  </li>
ingo@804:      *  <li>statistic: Creates a statistic with important figures.</li>
ingo@804:      *  <li>csv: Creates a csv file.</li>
ingo@804:      *  <li>odv: Creates a odv file.</li>
ingo@804:      * </ol>
ingo@804:      *
ingo@804:      * @param format Document which contains some export specific information.
ingo@804:      * @param inputData Contains some meta information to adjust the export
ingo@804:      * (e.g. width and height of a chart).
ingo@804:      * @param outputStream The output stream used to return the export.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param callContext The CallContext object.
ingo@804:      * @throws StateException if an error occured while creating the export
ingo@804:      * object.
tim@335:      */
tim@335:     public void out(
sascha@480:         Document              format,
tim@335:         Collection<InputData> inputData,
sascha@480:         OutputStream          outputStream,
sascha@480:         String                uuid,
sascha@480:         CallContext           callContext
tim@335:     ) throws StateException
tim@335:     {
tim@335:         log.debug("TimeSeriesOutputTransition.out");
tim@335: 
ingo@467:         String outputMode = XMLUtils.xpathString(
ingo@467:             format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE);
ingo@467: 
ingo@639:         String mode       = XMLUtils.xpathString(
ingo@639:             format, XPATH_EXPORT_MODE, ArtifactNamespaceContext.INSTANCE);
ingo@639: 
ingo@639:         if (mode == null || mode.equals("")) {
ingo@639:             mode = "img";
ingo@639:         }
ingo@639: 
ingo@467:         String mimeType = XMLUtils.xpathString(
ingo@467:             format, XPATH_MIME_TYPE, ArtifactNamespaceContext.INSTANCE);
tim@335: 
ingo@358:         CallMeta callMeta         = callContext.getMeta();
ingo@358: 
ingo@502:         int chartWidth   = 600;
ingo@502:         int chartHeight  = 400;
ingo@502:         boolean sVisible = false;
ingo@629:         int binCount     = 0;
ingo@629:         int binWidth     = 0;
ingo@629: 
ingo@629:         Map requestParameter = new HashMap();
ingo@502: 
ingo@502:         // lines are always visible. if lines should be configurable we need a
ingo@502:         // parameter in the user interface
ingo@502:         boolean lVisible = true;
ingo@502: 
ingo@502:         try {
ingo@502:             if (inputData != null) {
ingo@502:                 Iterator<InputData> it = inputData.iterator();
ingo@502:                 while (it.hasNext()) {
ingo@502:                     InputData ip      = it.next();
ingo@502:                     String optionName = ip.getName().trim();
ingo@629:                     requestParameter.put(optionName, ip.getValue());
ingo@502: 
ingo@502:                     if (optionName.equals("width")) {
ingo@502:                         chartWidth = Integer.parseInt(ip.getValue());
ingo@502:                     }
ingo@502:                     else if (optionName.equals("height")) {
ingo@502:                         chartHeight = Integer.parseInt(ip.getValue());
ingo@502:                     }
ingo@502:                     else if (optionName.equals("points")) {
ingo@502:                         sVisible = Boolean.parseBoolean(ip.getValue());
ingo@502:                     }
ingo@502:                 }
ingo@502:             }
ingo@502:         } catch (NumberFormatException e) {
ingo@725:             log.warn(e, e);
ingo@725:             XMLUtils.toStream(
ingo@725:                 feedFailure("not.a.number"),
ingo@725:                 outputStream);
ingo@725:             return;
ingo@502:         }
ingo@502: 
tim@335:         try {
ingo@639:             Collection<KeyValueDescibeData> parameters   =
ingo@639:                 getParameters(uuid);
ingo@639:             Collection<KeyValueDescibeData> measurements =
ingo@639:                 getMeasurements(uuid);
ingo@639:             Collection<KeyValueDescibeData> dates        =
ingo@639:                 getDates(uuid);
ingo@639: 
ingo@639:             Locale[] serverLocales =
ingo@639:                 RessourceFactory.getInstance().getLocales();
ingo@639:             Locale locale          =
ingo@639:                 callMeta.getPreferredLocale(serverLocales);
ingo@639: 
ingo@639:             ChartLabels chartLables = createChartLabels(locale, uuid);
ingo@639: 
ingo@639:             log.debug(
ingo@639:                 "Best locale - regarding intersection of server and " +
ingo@639:                 "browser locales -  is " + locale.toString()
ingo@639:             );
ingo@639: 
ingo@639:             String exportFormat = getExportFormat(mimeType);
ingo@639: 
ingo@639:             // CHART
tim@335:             if (outputMode.equalsIgnoreCase("chart")) {
tim@335:                 log.debug("Chart will be generated.");
tim@335: 
ingo@639:                 if (mode.equalsIgnoreCase("img")) {
ingo@639:                     createChart(
ingo@639:                         outputStream,
ingo@639:                         parameters,
ingo@639:                         measurements,
ingo@639:                         dates,
ingo@639:                         chartLables,
ingo@639:                         callContext,
ingo@639:                         uuid,
ingo@639:                         exportFormat,
ingo@639:                         locale,
ingo@639:                         chartWidth,
ingo@639:                         chartHeight,
ingo@639:                         lVisible,
ingo@639:                         sVisible,
ingo@639:                         callContext
ingo@639:                     );
ingo@639:                 }
ingo@639:                 else if (mode.equalsIgnoreCase("pdf")) {
ingo@1050:                     callContext.putContextValue("chart.width", chartWidth);
ingo@1050:                     callContext.putContextValue("chart.height", chartHeight);
ingo@1050:                     callContext.putContextValue("shapes.visible", sVisible);
ingo@1050:                     callContext.putContextValue("lines.visible", lVisible);
ingo@1050:                     callContext.putContextValue("locale", locale);
ingo@1050: 
ingo@639:                     createPDF(
ingo@639:                         outputStream,
ingo@639:                         parameters,
ingo@639:                         measurements,
ingo@639:                         dates,
ingo@639:                         chartLables,
ingo@639:                         uuid,
ingo@639:                         "A4",
ingo@639:                         callContext
ingo@639:                     );
ingo@639:                 }
ingo@639:                 else if (mode.equalsIgnoreCase("svg")) {
ingo@639:                     createSVG(
ingo@639:                         outputStream,
ingo@639:                         getParameters(uuid),
ingo@639:                         getMeasurements(uuid),
ingo@639:                         getDates(uuid),
ingo@639:                         createChartLabels(locale, uuid),
ingo@639:                         uuid,
ingo@639:                         locale,
ingo@639:                         chartWidth,
ingo@639:                         chartHeight,
ingo@639:                         lVisible,
ingo@639:                         sVisible,
ingo@639:                         callContext
ingo@639:                     );
ingo@639:                 }
ingo@639:             }
ingo@639:             // HISTOGRAM
ingo@639:             else if (outputMode.equalsIgnoreCase("histogram")) {
ingo@639:                 Collection results = (Collection) getChartResult(uuid, callContext);
ingo@639:                 requestParameter.put("locale", locale);
tim@335: 
ingo@617:                 Object[][] data = HistogramHelper.prepareHistogramData(
ingo@617:                     results, parameters, measurements, dates);
ingo@617: 
ingo@617:                 int size           = data.length;
ingo@617:                 Chart[] histograms = new Chart[size];
ingo@617: 
ingo@617:                 for (int i = 0; i < size; i++) {
ingo@617:                     ChartLabels labels = createHistogramLabels(
ingo@848:                         uuid, callContext, locale, data[i]);
ingo@617: 
ingo@617:                     ChartTheme theme   = createStyle(callContext);
ingo@617: 
ingo@617:                     histograms[i] = new DefaultHistogram(
ingo@629:                         labels, data[i], theme, requestParameter);
ingo@617:                 }
ingo@617: 
ingo@639:                 if (mode.equalsIgnoreCase("img")) {
ingo@639:                     ChartExportHelper.exportHistograms(
ingo@639:                         outputStream,
ingo@639:                         histograms,
ingo@639:                         exportFormat,
ingo@639:                         chartWidth,
ingo@639:                         chartHeight
ingo@639:                     );
ingo@639:                 }
ingo@639:                 else if (mode.equalsIgnoreCase("pdf")) {
ingo@1053:                     callContext.putContextValue("chart.width", chartWidth);
ingo@1053:                     callContext.putContextValue("chart.height", chartHeight);
ingo@1053: 
ingo@640:                     ChartExportHelper.exportHistogramsAsPDF(
ingo@640:                         outputStream,
ingo@640:                         histograms,
ingo@640:                         "A4",
ingo@1053:                         50F, 50F, 50F, 50F,
ingo@1053:                         callContext
ingo@640:                     );
ingo@639:                 }
ingo@639:                 else if (mode.equalsIgnoreCase("svg")) {
ingo@639:                     ChartExportHelper.exportHistogramsAsSVG(
ingo@639:                         outputStream,
ingo@639:                         histograms,
ingo@639:                         null,
ingo@639:                         chartWidth,
ingo@639:                         chartHeight
ingo@639:                     );
ingo@639:                 }
tim@335:             }
tim@335:             else if (outputMode.equalsIgnoreCase("csv")) {
tim@335:                 log.debug("CSV-File will be generated.");
sascha@452:                 Object result = getChartResult(uuid, callContext);
sascha@452:                 if (result instanceof Collection) {
sascha@452:                     this.createCSV(
sascha@452:                         outputStream,
sascha@452:                         (Collection<Result>)result);
sascha@452:                 }
tim@335:             } else if (outputMode.equalsIgnoreCase("statistics")) {
tim@335:                 log.debug("Statistics will be generated.");
sascha@446: 
sascha@446:                 Collection<StatisticSet> statistics;
sascha@446: 
sascha@454:                 Statistics s      = getStatisticsGenerator();
sascha@454:                 Object     result = getChartResult(uuid, callContext);
sascha@446: 
sascha@454:                 if (result != null && s != null) {
sascha@446:                     statistics = s.calculateStatistics(
sascha@454:                         result,
sascha@446:                         parameters,
sascha@446:                         measurements,
sascha@446:                         dates);
sascha@446:                 }
sascha@446:                 else {
sascha@446:                     statistics = new ArrayList<StatisticSet>();
sascha@446:                 }
sascha@446: 
ingo@851:                 Document doc = writeStatistics2XML(statistics, locale);
sascha@454: 
sascha@481:                 XMLUtils.toStream(doc, outputStream);
sascha@454: 
ingo@617:             }
ingo@617:             else if (outputMode.equalsIgnoreCase("odv")) {
tim@830:                 createODV(outputStream, uuid, callContext);
tim@335:             }
tim@335:         } catch (IOException e) {
tim@335:             log.error(e, e);
tim@335:             throw new StateException(e);
tim@335:         } catch (TechnicalChartException e) {
tim@335:             log.error(e, e);
tim@335:             throw new StateException(e);
tim@335:         } catch (StatisticsException e) {
tim@335:             log.error(e, e);
tim@335:             throw new StateException(e);
tim@335:         }
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
tim@830:      * @param outputStream
tim@830:      * @param uuid
tim@830:      * @throws IOException
tim@830:      * @throws StateException
tim@830:      */
sascha@835:     protected void createODV(OutputStream outputStream,
sascha@835:                              String uuid,
tim@830:                              CallContext callContext)
tim@830:                                                     throws IOException,
tim@830:                                                     StateException {
tim@830:         Collection<Result> odvResult = this.getODVResult(uuid);
tim@830:         this.createODV(outputStream, odvResult,uuid);
tim@830:     }
tim@830: 
tim@830: 
tim@830:     /**
ingo@804:      * Retrieves the export format (e.g. png, gif, jpeg).
ingo@804:      *
ingo@804:      * @param mime Export format specified by the incoming  request.
ingo@804:      * @return <i>mime</i> if it is supported - otherwise the first format in
ingo@804:      * {@link #IMG_EXPORT_FORMAT}.
ingo@804:      */
tim@335:     protected String getExportFormat(String mime) {
tim@335:         for(int i = 0; i < IMG_EXPORT_FORMAT.length; i++) {
tim@335:             if (mime.trim().toUpperCase().indexOf(IMG_EXPORT_FORMAT[i]) > 0)
tim@335:                 return IMG_EXPORT_FORMAT[i];
tim@335:         }
tim@335: 
tim@335:         // no format found relating to mimeType, default export as PNG
tim@335:         return IMG_EXPORT_FORMAT[0];
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Returns a collection containing all selected KeyValueDescibeData objects
ingo@804:      * of <i>parameters</i>.
ingo@804:      *
ingo@804:      * @param parameters A collection with KeyValueDescibeData objects.
ingo@804:      * @return a collection cleaned from unselected objects.
ingo@804:      * @deprecated
ingo@804:      */
tim@335:     protected Collection getCleanedParameters(Collection parameters) {
tim@335:         Iterator iter        = parameters.iterator();
tim@335:         Collection parameter = new Vector(parameters);
tim@335:         while (iter.hasNext()) {
tim@335:             KeyValueDescibeData data = (KeyValueDescibeData)iter.next();
tim@335:             if (!data.isSelected())
tim@335:                 parameter.remove(data);
tim@335:         }
tim@335: 
tim@335:         return parameter;
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Calls {@link #getCleanedParameters(java.util.Collection)} with the
ingo@804:      * collection returned by {@link #getParameters(java.lang.String)}.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return a cleaned collection.
ingo@804:      */
tim@335:     protected Collection getCleanedParameters(String uuid) {
tim@335:         return getCleanedParameters(getParameters(uuid));
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Create a csv file representing the data corresponding to the current
ingo@804:      * parameterization.
ingo@804:      *
ingo@804:      * @param out The output stream used to export the csv file.
ingo@804:      * @param results The data used for csv file creation.
ingo@804:      * @throws UnsupportedEncodingException if the encoding is not supported.
ingo@804:      * @throws IOException if an error occured while writing to output stream.
ingo@804:      * @throws StateException if an error occured while creating the csv file.
ingo@804:      */
ingo@368:     protected void createCSV(OutputStream out, Collection<Result> results)
ingo@368:     throws UnsupportedEncodingException, IOException, StateException
ingo@368:     {
ingo@368:         Iterator iter = results.iterator();
ingo@368:         Result   res  = iter.hasNext() ? (Result) iter.next() : null;
tim@335: 
ingo@368:         if (res == null)
ingo@368:             return;
ingo@368: 
ingo@368:         Profile profile = null;
ingo@368:         int     dataid  = res.getInteger("DATAID").intValue();
ingo@368: 
ingo@368:         // on meshes
ingo@368:         if (dataid == 2) {
ingo@368:             profile =  new DefaultProfile(
ingo@368:                 TIMESERIES_MESH_CSV_COLUMN_LABEL,
ingo@368:                 ',',
ingo@368:                 '"',
ingo@368:                 '"',
ingo@368:                 "CSV",
ingo@368:                 "ISO-8859-1");
ingo@368:         }
ingo@368: 
ingo@368:         // on timeseries
ingo@368:         else {
ingo@368:             profile =  new DefaultProfile(
ingo@368:                 TIMESERIES_TIMESERIES_CSV_COLUMN_LABEL,
ingo@368:                 ',',
ingo@368:                 '"',
ingo@368:                 '"',
ingo@368:                 "CSV",
ingo@368:                 "ISO-8859-1");
ingo@368:         }
ingo@368: 
ingo@368:         DefaultExport export = new DefaultExport(
ingo@368:             new DefaultDataCollector(TIMESERIES_CSV_PROFILE_COLUMNS));
ingo@368:         export.create(profile, out, results);
tim@335:     }
tim@335: 
ingo@368: 
tim@335:     /**
ingo@804:      * Create an odv file representing the data corresponding to the current
ingo@804:      * parameterization.
sascha@805:      *
ingo@804:      * @param outputStream The output stream used to export the odv file.
ingo@804:      * @param result The data used for odv file creation.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @throws IOException if an error occured while writing to output stream.
ingo@804:      * @throws StateException if an error occured while creating the odv file.
tim@335:      */
sascha@778:     protected void createODV(OutputStream outputStream,
tim@765:                              Collection result,
tim@765:                              String uuid)
tim@335:     throws IOException, StateException {
tim@335: 
tim@765:         Export export = new ODVExport(new SimpleOdvDataCollector(
tim@765:             TIMESERIES_ODV_PROFILE_NAMES),
tim@812:             this.getParameters(uuid),
tim@812:             this.getStartTime());
tim@335: 
tim@335:         if (result == null)
tim@335:             log.error("#################### RESULT == NULL #################");
tim@335:         export.create(TIMESERIES_ODV_PROFILE, outputStream, result);
tim@335:     }
tim@335: 
tim@335:     /**
tim@812:      * Method that returns the Starttime of an TimeSeries or
tim@812:      * null if it is not a TimeSeries.
tim@812:      * @return the Starttime of an TimeSeries or null if it is not a TimeSeries.
tim@812:      */
tim@812:     protected String getStartTime(){
tim@812:         InputData data = inputData.get(this.timeIntervalValueName);
tim@812:         if (data != null){
tim@812:             Object describeData = data.getObject();
tim@812:             if (describeData instanceof MinMaxDescribeData){
tim@816:                 String value = ((MinMaxDescribeData)describeData)
tim@816:                                 .getMinValue().toString();
tim@816:                 return value.substring(0,value.lastIndexOf(':'));
tim@812:             }
tim@812:             return null;
tim@812:         }else{
tim@812:             return null;
tim@812:         }
sascha@835: 
tim@812:     }
tim@812: 
tim@812:     /**
ingo@804:      * Returns the statistic generator.
ingo@804:      *
ingo@804:      * @return the statistic generator.
tim@335:      */
tim@335:     protected Statistics getStatisticsGenerator() {
tim@335:         Statistics s = new TimeseriesStatistics();
tim@335:         return s;
tim@335:     }
tim@335: 
ingo@804: 
ingo@804:     /**
ingo@804:      * Writes the statistic into an xml document.
ingo@804:      *
ingo@804:      * @param statistic Statistic to be written to xml document.
ingo@804:      * @return the xml document containing the statistic.
ingo@804:      */
ingo@851:     protected Document writeStatistics2XML(
ingo@851:         Collection<StatisticSet> statistic, Locale locale)
ingo@851:     {
tim@335:         ArtifactXMLUtilities xmlUtilities = new ArtifactXMLUtilities();
tim@335:         Document doc = XMLUtils.newDocument();
ingo@851: 
ingo@851:         NumberFormat format = NumberFormat.getInstance(locale);
ingo@851: 
tim@335:         if (statistic != null) {
ingo@804:             Node statisticResults = ArtifactXMLUtilities.createArtifactElement(doc,
tim@335:                     "statistics");
tim@335:             doc.appendChild(statisticResults);
tim@335:             Iterator<StatisticSet> it = statistic.iterator();
tim@335:             while (it.hasNext()) {
tim@335:                 StatisticSet set = it.next();
ingo@804:                 Element setElement = ArtifactXMLUtilities.createArtifactElement(doc,
tim@335:                                                                        "statistic");
tim@335:                 setElement.setAttribute("name", set.getName());
sascha@778: 
tim@335:                 Iterator<Statistic> sit = set.getStatistics().iterator();
tim@335:                 while (sit.hasNext()){
tim@335:                     Statistic s = sit.next();
ingo@804:                     Element result = ArtifactXMLUtilities.createArtifactElement(doc,
tim@335:                     "statistic-value");
tim@335:                     result.setAttribute("name", s.getKey());
ingo@851:                     result.setAttribute("value", format.format(s.getValue()));
tim@335:                     setElement.appendChild(result);
tim@335:                 }
tim@335:                 statisticResults.appendChild(setElement);
tim@335:             }
tim@335: 
tim@335:         }
tim@335:         return doc;
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Returns the name of the selected feature.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return the name of the selectef feature.
ingo@804:      */
tim@335:     protected String getSelectedFeatureName(String uuid) {
tim@335:         Collection values = getCollection(featureValuesName, uuid);
tim@335: 
tim@335:         if (values != null) {
tim@335:             Iterator it = values.iterator();
tim@335: 
tim@335:             while (it.hasNext()) {
tim@335:                 KeyValueDescibeData data = (KeyValueDescibeData) it.next();
ingo@610:                 return data.getValue();
ingo@610:             }
tim@335: 
ingo@610:             return "";
tim@335:         }
ingo@610:         return "";
tim@335:     }
tim@335: 
tim@335: 
tim@335:     /**
ingo@804:      * Creates a chart and writes it to <i>outputStream</i>.
ingo@804:      *
ingo@804:      * @param outputStream The stream used to write the chart to.
ingo@804:      * @param parameters A collection with parameters.
ingo@804:      * @param measurements A collection with measurements.
ingo@804:      * @param dates A collection with dates.
ingo@804:      * @param chartLables The labels used to decorate the chart.
ingo@804:      * @param context The CallContext.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param exportFormat The format the chart used to be exported as.
ingo@804:      * @param locale The Locale to specify the language.
ingo@804:      * @param width The width of the chart.
ingo@804:      * @param height The height of the chart.
ingo@804:      * @param linesVisible A boolean property to determine the visibility of
ingo@804:      * lines connecting two datapoins.
ingo@804:      * @param shapesVisible A boolean property to determine the visibility of
ingo@804:      * datapoints.
ingo@804:      * @param callContext The CallContext object.
ingo@804:      * @throws IOException if an error occured while writing to output stream.
ingo@804:      * @throws TechnicalChartException if an error occured while chart creation.
tim@335:      */
tim@335:     protected void createChart(
tim@335:         OutputStream outputStream,
tim@335:         Collection   parameters,
tim@335:         Collection   measurements,
tim@335:         Collection   dates,
tim@335:         ChartLabels  chartLables,
ingo@358:         CallContext  context,
tim@335:         String       uuid,
tim@335:         String       exportFormat,
tim@335:         Locale       locale,
tim@335:         int          width,
tim@335:         int          height,
tim@335:         boolean      linesVisible,
sascha@439:         boolean      shapesVisible,
sascha@439:         CallContext  callContext
tim@335:     )
tim@335:     throws IOException, TechnicalChartException
tim@335:     {
tim@335:         log.debug("Create chart.");
tim@335:         Chart chart = getChart(
tim@335:             chartLables,
ingo@358:             createStyle(context),
tim@335:             parameters,
tim@335:             measurements,
tim@335:             dates,
sascha@439:             getChartResult(uuid, callContext),
tim@335:             locale, // Locale
tim@335:             uuid,
tim@335:             linesVisible,
sascha@439:             shapesVisible,
sascha@439:             callContext
tim@335:         );
tim@335: 
tim@335:         if (chart == null) {
tim@335:             log.error("Could not initialize chart.");
tim@335:             return;
tim@335:         }
tim@335: 
tim@335:         log.debug(
tim@335:             "export chart as " + exportFormat +
tim@335:             " in " + width + "x" + height
tim@335:         );
tim@335: 
tim@335:         ChartExportHelper.exportImage(
tim@335:             outputStream,
tim@335:             chart.generateChart(),
tim@335:             exportFormat,
tim@335:             width,
tim@335:             height
tim@335:         );
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Creates a chart and writes it as pdf to <i>outputStream</i>.
ingo@804:      *
ingo@804:      * @param outputStream The stream used to write the chart to.
ingo@804:      * @param parameters A collection with parameters.
ingo@804:      * @param measurements A collection with measurements.
ingo@804:      * @param dates A collection with dates.
ingo@804:      * @param chartLables The labels used to decorate the chart.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param exportFormat The format the chart used to be exported as.
ingo@804:      * @param landscape A boolean property to determine the alignment of the
ingo@804:      * chart.
ingo@804:      * @param linesVisible A boolean property to determine the visibility of
ingo@804:      * lines connecting two datapoins.
ingo@804:      * @param shapesVisible A boolean property to determine the visibility of
ingo@804:      * datapoints.
ingo@804:      * @param locale The Locale to specify the language.
ingo@804:      * @param context The CallContext object.
ingo@804:      */
tim@335:     protected void createPDF(
tim@335:         OutputStream outputStream,
tim@335:         Collection   parameters,
tim@335:         Collection   measurements,
tim@335:         Collection   dates,
tim@335:         ChartLabels  chartLables,
tim@335:         String       uuid,
tim@335:         String       exportFormat,
ingo@358:         CallContext  context
tim@335:     ) {
tim@335:         Chart chart = getChart(
tim@335:             chartLables,
ingo@358:             createStyle(context),
tim@335:             parameters,
tim@335:             measurements,
tim@335:             dates,
sascha@452:             getChartResult(uuid, context),
ingo@1050:             (Locale) context.getContextValue("locale"),
tim@335:             uuid,
ingo@1050:             Boolean.TRUE.equals(context.getContextValue("lines.visible")),
ingo@1050:             Boolean.TRUE.equals(context.getContextValue("shapes.visible")),
sascha@439:             context
tim@335:         );
tim@335: 
tim@335:         if (chart == null) {
tim@335:             log.error("Could not initialize chart.");
tim@335:             return;
tim@335:         }
tim@335: 
tim@335:         ChartExportHelper.exportPDF(
tim@335:             outputStream,
tim@335:             chart.generateChart(),
tim@335:             "A4",
ingo@1050:             50F, 50F, 50F, 50F,
ingo@1050:             context
tim@335:         );
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Creates a chart and writes it as svg to <i>outputStream</i>.
ingo@804:      *
ingo@804:      * @param outputStream The stream used to write the chart to.
ingo@804:      * @param parameters A collection with parameters.
ingo@804:      * @param measurements A collection with measurements.
ingo@804:      * @param dates A collection with dates.
ingo@804:      * @param chartLables The labels used to decorate the chart.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param locale The Locale to specify the language.
ingo@804:      * @param width The width of the chart.
ingo@804:      * @param height The height of the chart.
ingo@804:      * @param linesVisible A boolean property to determine the visibility of
ingo@804:      * lines connecting two datapoins.
ingo@804:      * @param shapesVisible A boolean property to determine the visibility of
ingo@804:      * datapoints.
ingo@804:      * @param callContext The CallContext object.
ingo@804:      */
tim@335:     protected void createSVG(
tim@335:         OutputStream outputStream,
tim@335:         Collection   parameters,
tim@335:         Collection   measurements,
tim@335:         Collection   dates,
tim@335:         ChartLabels  chartLables,
tim@335:         String       uuid,
tim@335:         Locale       locale,
tim@335:         int          width,
tim@335:         int          height,
tim@335:         boolean      linesVisible,
ingo@358:         boolean      shapesVisible,
ingo@358:         CallContext  callContext
tim@335:     ) {
tim@335:         Chart chart = getChart(
tim@335:             chartLables,
ingo@358:             createStyle(callContext),
tim@335:             parameters,
tim@335:             measurements,
tim@335:             dates,
sascha@446:             getChartResult(uuid, callContext),
tim@335:             locale,
tim@335:             uuid,
tim@335:             linesVisible,
sascha@439:             shapesVisible,
sascha@439:             callContext
tim@335:         );
tim@335: 
tim@335:         if (chart == null) {
tim@335:             log.error("Could not initialize chart.");
tim@335:             return;
tim@335:         }
tim@335: 
tim@335:         ChartExportHelper.exportSVG(
tim@335:             outputStream,
tim@335:             chart.generateChart(),
tim@335:             null,
ingo@1048:             width, height
tim@335:         );
tim@335: 
tim@335:         log.debug("svg export finished.");
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * This method creates a chart and returns it. In normal case, this is the
ingo@804:      * only method to be overriden by subclasses to create other types of
ingo@804:      * charts.
ingo@804:      *
ingo@804:      * @param chartLables Labels used to decorate the chart.
ingo@804:      * @param theme The theme used to adjust the look of the chart.
ingo@804:      * @param parameters A collection with parameters this chart contains.
ingo@804:      * @param measurements A collection with measurement this chart contains.
ingo@804:      * @param dates A collection with dates this chart contains.
ingo@804:      * @param result The data collection used to be displayed in this chart.
ingo@804:      * @param locale The Locale used to determine the language.
ingo@804:      * @param uuid The uuid of the current artifact.
ingo@804:      * @param linesVisible A boolean property to determine the visibility of
ingo@804:      * lines connecting two points in a chart (not used in this chart type).
ingo@804:      * @param shapesVisible A boolean property to determine the visiblity of
ingo@804:      * datapoints in this chart (not used in this chart type).
ingo@804:      * @param callContext The CallContext object.
ingo@804:      * @return a timeseries chart.
ingo@804:      */
tim@335:     protected Chart getChart(
tim@335:         ChartLabels  chartLables,
ingo@358:         ChartTheme   theme,
tim@335:         Collection   parameters,
tim@335:         Collection   measurements,
tim@335:         Collection   dates,
ingo@429:         Object       result,
tim@335:         Locale       locale,
tim@335:         String       uuid,
tim@335:         boolean      linesVisible,
sascha@439:         boolean      shapesVisible,
sascha@439:         CallContext  callContext
tim@335:     ) {
tim@335:         Chart chart = null;
tim@335: 
tim@335:         if (CACHE_CHART) {
tim@335:             log.info("Try to get timeseries chart from cache.");
sascha@439:             chart = (Chart) getChartFromCache(uuid, callContext);
tim@335:         }
tim@335: 
tim@335:         if (chart != null)
tim@335:             return chart;
tim@335: 
tim@335:         log.info("Chart not in cache yet.");
tim@335:         chart = new TimeSeriesChart(
tim@335:             chartLables,
ingo@358:             theme,
tim@335:             parameters,
tim@335:             measurements,
tim@335:             dates,
ingo@429:             (Collection)result,
tim@335:             timeGapDefinitions,
tim@335:             locale,
tim@335:             linesVisible,
tim@335:             shapesVisible
tim@335:         );
tim@335:         chart.generateChart();
tim@335: 
tim@335:         if (CACHE_CHART) {
tim@335:             log.info("Put chart into cache.");
tim@335:             purifyChart(chart, uuid);
tim@335:         }
tim@335: 
tim@335:         return chart;
tim@335:     }
tim@335: 
ingo@804: 
ingo@804:     /**
ingo@804:      * Fetches the ChartTheme from <i>callContext</i> and returns it.
ingo@804:      *
ingo@804:      * @param callContext CallContext objects storing a chart theme.
ingo@804:      * @return a chart theme.
ingo@804:      */
ingo@358:     protected ChartTheme createStyle(CallContext callContext) {
ingo@358:         log.debug("Fetch chart theme from global context");
tim@335: 
ingo@358:         GNVArtifactContext context =
ingo@358:             (GNVArtifactContext) callContext.globalContext();
ingo@358: 
ingo@358:         XMLChartTheme theme = (XMLChartTheme) context.get(
sascha@443:             GNVArtifactContext.CHART_TEMPLATE_KEY);
tim@335: 
tim@335:         return theme;
tim@335:     }
tim@335: 
ingo@804:     /**
ingo@804:      * Creates a ChartLabels object storing different labels used to decorate a
ingo@804:      * chart.
ingo@804:      *
ingo@804:      * @param locale The Locale object to adjust the language of labels.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return the chart labels.
ingo@804:      */
ingo@492:     protected ChartLabels createChartLabels(Locale locale, String uuid) {
ingo@492:         return new ChartLabels(
ingo@492:             createChartTitle(locale, uuid),
ingo@492:             createChartSubtitle(locale, uuid),
ingo@492:             RessourceFactory.getInstance().getRessource(
ingo@492:                 locale,
ingo@492:                 domainLable,
ingo@492:                 domainLable
ingo@492:             )
ingo@492:         );
ingo@492:     }
ingo@492: 
tim@335: 
ingo@804:     /**
ingo@804:      * Creates and returns the chart title.
ingo@804:      *
ingo@804:      * @param locale The Locale used to adjust the language of the title.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return the name of the selected fis.
ingo@804:      */
tim@335:     protected String createChartTitle(Locale locale, String uuid) {
tim@335:         return getFisName(locale);
tim@335: 
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@839:      * Creates and returns the subtitle of a chart. The subtitle in this class
ingo@839:      * contains the station and the time interval.
ingo@804:      *
ingo@804:      * @param locale The Locale used to adjust the language of the subtitle.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return the selected feature.
ingo@804:      */
tim@335:     protected String createChartSubtitle(Locale locale, String uuid) {
ingo@839:         String subtitle = "";
ingo@839:         subtitle       += getSelectedFeatureName(uuid);
ingo@839: 
ingo@839:         InputData data = inputData.get(timeIntervalValueName);
ingo@839:         if (data != null){
ingo@839:             Object describeData = data.getObject();
ingo@839:             if (describeData instanceof MinMaxDescribeData) {
ingo@839:                 MinMaxDescribeData tmp = (MinMaxDescribeData) describeData;
ingo@839: 
ingo@839:                 DateFormat format = DateFormat.getDateTimeInstance(
ingo@839:                     DateFormat.MEDIUM, DateFormat.SHORT, locale);
ingo@839: 
ingo@839:                 String lDateStr = (String) tmp.getMinValue();
ingo@839:                 String rDateStr = (String) tmp.getMaxValue();
ingo@839: 
ingo@839:                 try {
ingo@839:                     Date lDate = srcFormat.parse(lDateStr);
ingo@839:                     Date rDate = srcFormat.parse(rDateStr);
ingo@839: 
ingo@839:                     String interval = format.format(lDate);
ingo@839:                     interval       += " - ";
ingo@839:                     interval       += format.format(rDate);
ingo@839: 
ingo@839:                     if (subtitle != null && subtitle.length() > 0)
ingo@839:                         subtitle += ", ";
ingo@839: 
ingo@839:                     subtitle += interval;
ingo@839:                 }
ingo@839:                 catch (ParseException pe) {
ingo@839:                     log.error(pe, pe);
ingo@839:                 }
ingo@839:             }
ingo@839:         }
ingo@839: 
ingo@839:         return subtitle;
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Creates and returns labels to decorate histograms.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @param context The CallContext object.
ingo@804:      * @param data An array storing strings.
ingo@804:      * @return A ChartLabels object with the 1st string in <i>data</i> as title.
ingo@804:      */
ingo@617:     protected ChartLabels createHistogramLabels(
ingo@848:         String uuid, CallContext context, Locale locale, Object[] data)
ingo@617:     {
ingo@848:         RessourceFactory fac = RessourceFactory.getInstance();
ingo@848: 
ingo@848:         return new ChartLabels(
ingo@848:             (String) data[0],
ingo@848:             "",
ingo@848:             "",
ingo@848:             fac.getRessource(locale, "histogram.axis.range.title", ""));
ingo@617:     }
ingo@617: 
ingo@617: 
ingo@804:     /**
ingo@804:      * Returns the selected fis name.
ingo@804:      *
ingo@804:      * @param locale The Locale object used to adjust the language.
ingo@804:      * @return the name of the fis.
ingo@804:      */
tim@335:     protected String getFisName(Locale locale) {
tim@335:         String    returnValue = "";
tim@335:         InputData input       = inputData.get("fisname");
tim@335: 
tim@335:         if (input != null) {
tim@335:             String value = input.getValue();
tim@335: 
tim@335:             returnValue = RessourceFactory.getInstance().getRessource(
tim@335:                 locale,
tim@335:                 value,
tim@335:                 value
tim@335:             );
tim@335:         }
tim@335:         return returnValue;
tim@335:     }
tim@335: 
tim@335: 
ingo@804:     /**
ingo@804:      * Returns the name of the selected object in the collection specified by
ingo@804:      * <i>key</i>.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifat.
ingo@804:      * @param key A key to specify a collection.
ingo@804:      * @return the name of the selected item.
ingo@804:      */
ingo@492:     protected String getSelectedInputDataName(String uuid, String key) {
ingo@492:         Collection values = getCollection(key, uuid);
ingo@492: 
ingo@492:         if (values != null) {
ingo@492:             Iterator it = values.iterator();
ingo@492: 
ingo@492:             while (it.hasNext()) {
ingo@492:                 KeyValueDescibeData data = (KeyValueDescibeData) it.next();
ingo@492: 
ingo@492:                 if (data.isSelected()) {
ingo@492:                     return data.getValue();
ingo@492:                 }
ingo@492:             }
ingo@492:         }
ingo@492:         return null;
ingo@492:     }
ingo@492: 
ingo@492: 
ingo@804:     /**
ingo@804:      * Returns a collection of selected parameters.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return selected parameters.
ingo@804:      */
tim@335:     protected Collection<KeyValueDescibeData> getParameters(String uuid) {
tim@335:         return this.getCollection(parameterValuesName, uuid);
tim@335:     }
tim@335: 
ingo@804:     /**
ingo@804:      * Returns a collection of selected measurements.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return selected measurements.
ingo@804:      */
tim@335:     protected Collection<KeyValueDescibeData> getMeasurements(String uuid) {
tim@335:         return this.getCollection(measuremenValueName, uuid);
tim@335:     }
ingo@804: 
ingo@804:     /**
ingo@804:      * Returns a collection of selected dates.
ingo@804:      *
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return selected dates.
ingo@804:      */
tim@335:     protected Collection<KeyValueDescibeData> getDates(String uuid) {
tim@335:         return this.getCollection(dateValueName,uuid);
tim@335:     }
tim@335: 
tim@335:     @Override
tim@335:     public void setup(Node configuration) {
tim@335:         super.setup(configuration);
tim@335:         String featureNameValue = Config.getStringXPath(configuration,
tim@335:                 "value-names/value-name[@name='feature']/@value");
tim@335:         if (featureNameValue != null) {
tim@335:             this.featureValuesName = featureNameValue;
tim@335:         }
tim@335:         String parameterNameValue = Config.getStringXPath(configuration,
tim@335:                 "value-names/value-name[@name='parameter']/@value");
tim@335:         if (parameterNameValue != null) {
tim@335:             this.parameterValuesName = parameterNameValue;
tim@335:         }
tim@335:         String measurementNameValue = Config.getStringXPath(configuration,
tim@335:                 "value-names/value-name[@name='measurement']/@value");
tim@335:         if (measurementNameValue != null) {
tim@335:             this.measuremenValueName = measurementNameValue;
tim@335:         }
tim@812:         String timeIntervalValue = Config.getStringXPath(configuration,
tim@812:                 "value-names/value-name[@name='timeinterval']/@value");
tim@812:         if (timeIntervalValue != null){
tim@812:             this.timeIntervalValueName = timeIntervalValue;
tim@812:         }
sascha@778: 
tim@335:         String dateNameValue = Config.getStringXPath(configuration,
tim@335:         "value-names/value-name[@name='date']/@value");
tim@335:         if (dateNameValue != null) {
tim@335:             this.dateValueName = dateNameValue;
tim@335:         }
tim@335:         if (timeGapDefinitions == null){
tim@335:             Element gapDefinition =  (Element)Config.getNodeXPath(configuration,
tim@335:                                                                  "time-gap-definition");
tim@335:             synchronized (this.getClass()) {
tim@335:                 if (gapDefinition != null){
tim@335:                     String link = gapDefinition.getAttribute("xlink:href");
tim@335:                     if (link != null ){
tim@335:                         String absolutFileName = Config.replaceConfigDir(link);
tim@335:                         gapDefinition = (Element)new ArtifactXMLUtilities().
tim@335:                                                      readConfiguration(absolutFileName);
tim@335:                     }
sascha@778: 
sascha@778:                     NodeList gapDefinitions = Config.getNodeSetXPath(gapDefinition,
tim@335:                                                                     "/time-gaps/time-gap");
tim@335:                     if (gapDefinition != null){
tim@335:                         timeGapDefinitions = new ArrayList<TimeGap>(gapDefinitions.
tim@335:                                                                     getLength());
tim@335:                         for (int i = 0; i < gapDefinitions.getLength(); i++){
tim@335:                             Element gapNode = (Element)gapDefinitions.item(i);
tim@335:                             String unit = gapNode.getAttribute("unit");
tim@335:                             int key = Integer.parseInt(gapNode.getAttribute("key"));
tim@335:                             int value = Integer.parseInt(gapNode.getAttribute("gap"));
tim@335:                             log.info("Add new Timegap: "+key+" "+value+" "+ unit);
sascha@778:                             timeGapDefinitions.add(new DefaultTimeGap(unit,
sascha@778:                                                                       key,
tim@335:                                                                       value));
tim@335:                         }
tim@335:                     }
tim@335:                 }
tim@335:             }
tim@335:         }
tim@335:     }
ingo@610: 
ingo@804: 
tim@335:     /**
ingo@804:      * Creates a <code>NamedArrayList</code> storing some <code>
ingo@804:      * KeyValueDescibeData</code> objects found in the input data with the key
ingo@804:      * <i>collectionName</i>.
ingo@804:      *
ingo@804:      * @param collectionName String to specify the input data.
ingo@804:      * @param uuid The UUID of the current artifact.
ingo@804:      * @return a collection with values from input data.
tim@335:      */
tim@335:     protected Collection<KeyValueDescibeData> getCollection(
ingo@610:         String collectionName,
ingo@610:         String uuid)
ingo@610:     {
ingo@838:         log.debug("Search for input data: " + collectionName);
ingo@610:         NamedCollection<KeyValueDescibeData> c = new NamedArrayList<KeyValueDescibeData>(collectionName);
tim@335: 
ingo@838:         InputData data = null;
ingo@838:         State parent   = this;
ingo@838:         do {
ingo@838:             data = parent.inputData().get(collectionName);
ingo@838: 
ingo@838:             if (data != null) {
ingo@838:                 break;
ingo@838:             }
ingo@838:         }
ingo@838:         while ((parent = parent.getParent()) != null);
ingo@838: 
ingo@610:         if (data == null) {
ingo@610:             log.warn("No collection found with name: " + collectionName);
ingo@610:             return c;
tim@335:         }
ingo@610: 
ingo@615:         String[] descs  = data.getDescription();
ingo@615:         String[] values = data.splitValue();
ingo@615:         int        size = values.length;
ingo@615: 
ingo@615:         for (int i = 0; i < size; i++){
ingo@615:             c.add(new DefaultKeyValueDescribeData(
ingo@615:                 values[i], descs[i], getID()));
ingo@615:         }
ingo@610: 
ingo@610:         return c;
tim@335:     }
tim@335: }
tim@335: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :