tim@335: /**
tim@335:  *
tim@335:  */
tim@335: package de.intevation.gnv.state.timeseries;
tim@335: 
sascha@480: import au.com.bytecode.opencsv.CSVWriter;
sascha@480: 
sascha@480: import de.intevation.artifactdatabase.Config;
sascha@480: import de.intevation.artifactdatabase.XMLUtils;
sascha@480: 
sascha@480: import de.intevation.artifacts.ArtifactNamespaceContext;
sascha@480: import de.intevation.artifacts.CallContext;
sascha@480: import de.intevation.artifacts.CallMeta;
sascha@480: import de.intevation.artifacts.PreferredLocale;
sascha@480: 
sascha@480: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
sascha@480: 
sascha@480: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
sascha@480: 
sascha@480: import de.intevation.gnv.chart.Chart;
sascha@480: import de.intevation.gnv.chart.ChartLabels;
sascha@480: import de.intevation.gnv.chart.TimeSeriesChart;
sascha@480: import de.intevation.gnv.chart.XMLChartTheme;
sascha@480: 
sascha@480: import de.intevation.gnv.chart.exception.TechnicalChartException;
sascha@480: 
sascha@480: import de.intevation.gnv.exports.ChartExportHelper;
sascha@480: import de.intevation.gnv.exports.DefaultDataCollector;
sascha@480: import de.intevation.gnv.exports.DefaultExport;
sascha@480: import de.intevation.gnv.exports.DefaultProfile;
sascha@480: 
sascha@480: import de.intevation.gnv.exports.Export.Profile;
sascha@480: 
sascha@480: import de.intevation.gnv.exports.SimpleOdvDataCollector;
sascha@480: 
sascha@480: import de.intevation.gnv.geobackend.base.Result;
sascha@480: 
sascha@480: import de.intevation.gnv.state.InputData;
sascha@480: import de.intevation.gnv.state.OutputStateBase;
sascha@480: 
sascha@480: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
sascha@480: import de.intevation.gnv.state.describedata.NamedCollection;
sascha@480: 
sascha@480: import de.intevation.gnv.state.exception.StateException;
sascha@480: 
sascha@480: import de.intevation.gnv.statistics.Statistic;
sascha@480: import de.intevation.gnv.statistics.StatisticSet;
sascha@480: import de.intevation.gnv.statistics.Statistics;
sascha@480: import de.intevation.gnv.statistics.TimeseriesStatistics;
sascha@480: 
sascha@480: import de.intevation.gnv.statistics.exception.StatisticsException;
sascha@480: 
sascha@480: import de.intevation.gnv.timeseries.gap.DefaultTimeGap;
sascha@480: import de.intevation.gnv.timeseries.gap.TimeGap;
sascha@480: 
sascha@480: import de.intevation.gnv.utils.ArtifactXMLUtilities;
sascha@480: 
tim@335: import java.io.File;
sascha@480: import java.io.IOException;
tim@335: import java.io.OutputStream;
tim@335: import java.io.UnsupportedEncodingException;
sascha@480: 
tim@335: import java.util.ArrayList;
tim@335: import java.util.Collection;
tim@335: import java.util.Iterator;
tim@335: import java.util.List;
tim@335: import java.util.Locale;
tim@335: import java.util.Vector;
tim@335: 
tim@335: import org.apache.log4j.Logger;
sascha@480: 
sascha@480: import org.jfree.chart.ChartTheme;
sascha@480: 
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@335: 
tim@335: /**
sascha@481:  * @author Tim Englich    (tim.englich@intevation.de)
sascha@481:  * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
tim@335:  */
tim@335: public class TimeSeriesOutputState extends OutputStateBase {
tim@335: 
tim@335:     protected static final boolean CACHE_CHART =
tim@335:         Boolean.parseBoolean(System.getProperty("cache.chart", "false"));
tim@335: 
tim@335:     protected static final boolean PDF_FORMAT_LANDSCAPE =
tim@335:         Boolean.parseBoolean(System.getProperty("export.pdf.landscape","true"));
tim@335: 
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: 
tim@335:     private static List<TimeGap> timeGapDefinitions = null;
tim@335: 
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";
ingo@368: 
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@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@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: 
tim@335:     public static final String [] TIMESERIES_ODV_PROFILE_NAMES = {
tim@335:           "CRUISE",
tim@335:           "STATION",
tim@335:           "TYPE",
tim@335:           "SHAPE",
tim@335:           "BOTDEPTH",
tim@335:           "DEPTH",
tim@335:           "TIMEVALUE",
tim@335:           "DATAVALUE",
tim@335:           "PARAMETER"
tim@335:     };
tim@335: 
tim@335: 
tim@335:     public static final String [] ODV_COLUMN_HEADER = {
tim@335:         "Cruise",
tim@335:         "Station",
tim@335:         "Type",
tim@335:         "Longitude [deegrees_east]",
tim@335:         "Latitude [deegrees_north]",
tim@335:         "Bot. Depth [m]",
tim@335:         "Depth [m]",
tim@335:         "Date/Time",
tim@335:         "Value",
tim@335:         "Parameterid"
tim@335:     };
tim@335: 
tim@335:     /**
tim@335:      * Profile for exporting data to odv
tim@335:      * TODO Change TIMESERIES_PROFILE_NAMES, which belong to CSV exports
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: 
tim@335:     /**
tim@335:      * Constructor
tim@335:      */
tim@335:     public TimeSeriesOutputState() {
tim@335:         super();
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.transition.OutputTransition#out(java.lang.String,
tim@335:      *      java.util.Collection, java.io.OutputStream, java.lang.String,
tim@335:      *      de.intevation.artifacts.CallMeta)
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@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@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@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@502:             log.error(e, e);
ingo@502:             throw new StateException(e);
ingo@502:         }
ingo@502: 
tim@335:         try {
tim@335:             if (outputMode.equalsIgnoreCase("chart")) {
tim@335:                 log.debug("Chart will be generated.");
tim@335: 
tim@335:                 PreferredLocale[] locales = callMeta.getLanguages();
tim@335:                 Locale[] serverLocales    =
tim@335:                     RessourceFactory.getInstance().getLocales();
tim@335:                 Locale locale             =
tim@335:                     callMeta.getPreferredLocale(serverLocales);
tim@335: 
tim@335:                 log.debug(
tim@335:                     "Best locale - regarding intersection of server and " +
tim@335:                     "browser locales -  is " + locale.toString()
tim@335:                 );
tim@335: 
tim@335:                 Collection parameters   = this.getCleanedParameters(uuid);
tim@335:                 Collection measurements = this.getMeasurements(uuid);
tim@335:                 Collection dates        = this.getDates(uuid);
tim@335: 
ingo@492:                 ChartLabels chartLables = createChartLabels(locale, uuid);
tim@335: 
tim@335:                 String exportFormat = getExportFormat(mimeType);
tim@335: 
tim@335:                 this.createChart(
tim@335:                     outputStream,
tim@335:                     parameters,
tim@335:                     measurements,
tim@335:                     dates,
tim@335:                     chartLables,
ingo@358:                     callContext,
tim@335:                     uuid,
tim@335:                     exportFormat,
tim@335:                     locale,
tim@335:                     chartWidth,
tim@335:                     chartHeight,
ingo@502:                     lVisible,
ingo@502:                     sVisible,
sascha@439:                     callContext
tim@335:                 );
tim@335:             }
tim@335:             else if (outputMode.equalsIgnoreCase("pdf")) {
tim@335:                 log.debug("Output mode == pdf");
tim@335: 
tim@335:                 Locale[] serverLocales    =
tim@335:                     RessourceFactory.getInstance().getLocales();
tim@335:                 Locale locale             =
tim@335:                     callMeta.getPreferredLocale(serverLocales);
tim@335: 
tim@335:                 log.debug(
tim@335:                     "Best locale - regarding intersection of server and " +
tim@335:                     "browser locales -  is " + locale.toString()
tim@335:                 );
tim@335: 
tim@335:                 createPDF(
tim@335:                     outputStream,
tim@335:                     getCleanedParameters(uuid),
tim@335:                     getMeasurements(uuid),
tim@335:                     getDates(uuid),
tim@335:                     new ChartLabels(
tim@335:                         createChartTitle(locale, uuid),
tim@335:                         createChartSubtitle(locale, uuid),
ingo@342:                         RessourceFactory.getInstance().getRessource(
ingo@342:                             locale,
ingo@342:                             domainLable,
ingo@342:                             domainLable
ingo@342:                         )
ingo@342:                     ),
tim@335:                     uuid,
tim@335:                     "A4",
tim@335:                     true,
ingo@502:                     lVisible,
ingo@502:                     sVisible,
tim@335:                     locale,
ingo@358:                     callContext
tim@335:                 );
tim@335:             }
tim@335:             else if (outputMode.equalsIgnoreCase("svg")) {
tim@335:                 log.debug("Output mode == svg");
tim@335: 
tim@335:                 Locale[] serverLocales    =
tim@335:                     RessourceFactory.getInstance().getLocales();
tim@335:                 Locale locale             =
tim@335:                     callMeta.getPreferredLocale(serverLocales);
tim@335: 
tim@335:                 log.debug(
tim@335:                     "Best locale - regarding intersection of server and " +
tim@335:                     "browser locales -  is " + locale.toString()
tim@335:                 );
tim@335: 
tim@335:                 createSVG(
tim@335:                     outputStream,
tim@335:                     getCleanedParameters(uuid),
tim@335:                     getMeasurements(uuid),
tim@335:                     getDates(uuid),
tim@335:                     new ChartLabels(
tim@335:                         createChartTitle(locale, uuid),
tim@335:                         createChartSubtitle(locale, uuid),
ingo@342:                         RessourceFactory.getInstance().getRessource(
ingo@342:                             locale,
ingo@342:                             domainLable,
ingo@342:                             domainLable
ingo@342:                         )
tim@335:                     ),
tim@335:                     uuid,
tim@335:                     locale,
ingo@502:                     chartWidth,
ingo@502:                     chartHeight,
ingo@502:                     lVisible,
ingo@502:                     sVisible,
ingo@358:                     callContext
tim@335:                 );
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:                     Collection<KeyValueDescibeData> parameters = 
sascha@454:                         getParameters(uuid);
sascha@454: 
sascha@446:                     Collection<KeyValueDescibeData> measurements = 
sascha@454:                         getMeasurements(uuid);
sascha@454: 
sascha@446:                     Collection<KeyValueDescibeData> dates = 
sascha@454:                          getDates(uuid);
sascha@454: 
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: 
sascha@454:                 Document doc = writeStatistics2XML(statistics);
sascha@454: 
sascha@481:                 XMLUtils.toStream(doc, outputStream);
sascha@454: 
tim@335:             } else if (outputMode.equalsIgnoreCase("odv")) {
tim@335:                 Collection<Result> odvResult = this.getODVResult(uuid);
tim@335:                 this.createODV(outputStream, odvResult);
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: 
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: 
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: 
tim@335:     protected Collection getCleanedParameters(String uuid) {
tim@335:         return getCleanedParameters(getParameters(uuid));
tim@335:     }
tim@335: 
tim@335: 
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:     /**
tim@335:      * TODO Result is not used at the moment. Change result with correct data.
tim@335:      */
tim@335:     protected void createODV(OutputStream outputStream, Collection result)
tim@335:     throws IOException, StateException {
tim@335: 
tim@335:         DefaultExport export = new DefaultExport(new SimpleOdvDataCollector(
tim@335:             TIMESERIES_ODV_PROFILE_NAMES));
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@335:      * @return
tim@335:      */
tim@335:     protected Statistics getStatisticsGenerator() {
tim@335:         Statistics s = new TimeseriesStatistics();
tim@335:         return s;
tim@335:     }
tim@335: 
tim@335:     protected Document writeStatistics2XML( Collection<StatisticSet> statistic) {
tim@335:         ArtifactXMLUtilities xmlUtilities = new ArtifactXMLUtilities();
tim@335:         Document doc = XMLUtils.newDocument();
tim@335:         if (statistic != null) {
tim@335:             Node statisticResults = xmlUtilities.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();
tim@335:                 Element setElement = xmlUtilities.createArtifactElement(doc,
tim@335:                                                                        "statistic");
tim@335:                 setElement.setAttribute("name", set.getName());
tim@335:                 
tim@335:                 Iterator<Statistic> sit = set.getStatistics().iterator();
tim@335:                 while (sit.hasNext()){
tim@335:                     Statistic s = sit.next();
tim@335:                     Element result = xmlUtilities.createArtifactElement(doc,
tim@335:                     "statistic-value");
tim@335:                     result.setAttribute("name", s.getKey());
tim@335:                     result.setAttribute("value", s.getStringValue());
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: 
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();
tim@335: 
tim@335:                 if (data.isSelected()) {
tim@335:                     return data.getValue();
tim@335:                 }
tim@335:             }
tim@335:         }
tim@335:         return null;
tim@335:     }
tim@335: 
tim@335: 
tim@335:     /**
tim@335:      * @param outputStream
tim@335:      * @param parameters
tim@335:      * @param measurements
tim@335:      * @param timeSeriesName
tim@335:      * @param chartStyle
tim@335:      * @param chartLables
tim@335:      * @throws IOException
tim@335:      * @throws TechnicalChartException
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: 
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,
tim@335:         boolean      landscape,
ingo@358:         boolean      linesVisible,
ingo@358:         boolean      shapesVisible,
tim@335:         Locale       locale,
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),
tim@335:             locale,
tim@335:             uuid,
tim@335:             linesVisible,
sascha@439:             shapesVisible,
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",
tim@335:             PDF_FORMAT_LANDSCAPE,
tim@335:             50F, 50F, 50F, 50F
tim@335:         );
tim@335:     }
tim@335: 
tim@335: 
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,
tim@335:             600, 400
tim@335:         );
tim@335: 
tim@335:         log.debug("svg export finished.");
tim@335:     }
tim@335: 
tim@335: 
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@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@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: 
tim@335:     protected String createChartTitle(Locale locale, String uuid) {
tim@335:         return getFisName(locale);
tim@335: 
tim@335:     }
tim@335: 
tim@335: 
tim@335:     protected String createChartSubtitle(Locale locale, String uuid) {
tim@335:         return getSelectedFeatureName(uuid);
tim@335:     }
tim@335: 
tim@335: 
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@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: 
tim@335:     protected Collection<KeyValueDescibeData> getParameters(String uuid) {
tim@335:         return this.getCollection(parameterValuesName, uuid);
tim@335:     }
tim@335: 
tim@335:     protected Collection<KeyValueDescibeData> getMeasurements(String uuid) {
tim@335:         return this.getCollection(measuremenValueName, uuid);
tim@335:     }
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@335:         
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:                     }
tim@335:                     
tim@335:                     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);
tim@335:                             timeGapDefinitions.add(new DefaultTimeGap(unit, 
tim@335:                                                                       key, 
tim@335:                                                                       value));
tim@335:                         }
tim@335:                     }
tim@335:                     
tim@335:                 }
tim@335:             }
tim@335:         }
tim@335:     }
tim@335:     
tim@335:     /**
tim@335:      * @param collectionName
tim@335:      * @return
tim@335:      */
tim@335:     protected Collection<KeyValueDescibeData> getCollection(
tim@335:                                                             String collectionName, 
tim@335:                                                             String uuid) {
tim@335:         Iterator<Object> it = this.getDescibeData(uuid).iterator();
tim@335:         while (it.hasNext()) {
tim@335: 
tim@335:             Object o = it.next();
tim@335: 
tim@335:             if (o instanceof NamedCollection<?>) {
tim@335:                 NamedCollection<KeyValueDescibeData> nc = (NamedCollection<KeyValueDescibeData>) o;
tim@335:                 if (nc.getName().equals(collectionName)) {
tim@335:                     return nc;
tim@335:                 }
tim@335:             }
tim@335:         }
tim@335:         return null;
tim@335:     }
tim@335: }
tim@335: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :