changeset 9196:87c08fa2da86

Merge
author gernotbelger
date Fri, 29 Jun 2018 14:54:40 +0200
parents a4121ec450d6 (diff) c373909fb7ca (current diff)
children fb5272746c74
files
diffstat 68 files changed, 572 insertions(+), 1060 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationExportableResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationExportableResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -18,7 +18,7 @@
 /**
  * @author Domenico Nardi Tironi
  */
-public abstract class AbstractCalculationExportableResult<RESULTS extends AbstractCalculationResults<?>> extends AbstractCalculationResult {
+public abstract class AbstractCalculationExportableResult extends AbstractCalculationResult {
 
     private static final long serialVersionUID = 1L;
 
@@ -26,11 +26,11 @@
         super(label, rows);
     }
 
-    public abstract void writeCSVHeader(ExportContextCSV exportContextCSV, final RESULTS results, final RiverInfo river);
+    public abstract void writeCSVHeader(ExportContextCSV exportContextCSV, final RiverInfo river);
 
-    public final void writeCsv(final ExportContextCSV exportContextCSV, final RESULTS results) {
+    public final void writeCsv(final ExportContextCSV exportContextCSV) {
 
-        writeCSVResultMetadata(exportContextCSV, results);
+        writeCSVResultMetadata(exportContextCSV);
         // wenn resultsmetadata null sind!? keine neue zeile
         // writer.writeNext(new String[] { "" }); // break line in den Implementationen,
         // weil es sein kann, dass KEINE ResultMetadata geschrieben werden; dann wäre eine Leerzeile überflüssig
@@ -38,41 +38,40 @@
         /* now the value rows */
         final Collection<ResultRow> rows = getRows();
         for (final ResultRow row : rows)
-            writeCSVRow(exportContextCSV, results, row);
+            writeCSVRow(exportContextCSV, row);
     }
 
-    protected abstract void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final RESULTS results);
+    protected abstract void writeCSVResultMetadata(final ExportContextCSV exportContextCSV);
 
-    protected void writeCSVRow(final ExportContextCSV exportContextCSV, final RESULTS results, final ResultRow row) {
-        final String[] formattedRow = formatCSVRow(exportContextCSV, results, row);
+    protected void writeCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+        final String[] formattedRow = formatCSVRow(exportContextCSV, row);
         exportContextCSV.writeCSVLine(formattedRow);
-
     }
 
-    protected abstract String[] formatCSVRow(ExportContextCSV exportContextCSV, final RESULTS results, final ResultRow row);
+    protected abstract String[] formatCSVRow(ExportContextCSV exportContextCSV, final ResultRow row);
 
-    protected abstract String[] formatPDFRow(ExportContextCSV exportContextPDF, RESULTS results, ResultRow row);
+    protected abstract String[] formatPDFRow(ExportContextPDF exportContextPDF, ResultRow row);
 
-    public JasperDesigner addReport(final ExportContextCSV exportContextPDF, final RESULTS results, final JasperReporter reporter,
-            final MetaAndTableJRDataSource source) throws JRException {
+    public JasperDesigner addReport(final ExportContextPDF exportContext, final JasperReporter reporter, final MetaAndTableJRDataSource source)
+            throws JRException {
 
         final JasperDesigner design = reporter.addReport(getJasperFile(), source);
-        addJRTableHeader(exportContextPDF, source, results);
-        addJRTableData(exportContextPDF, source, results);
+        addJRTableHeader(exportContext, source);
+        addJRTableData(exportContext, source);
         return design;
     }
 
     protected abstract String getJasperFile();
 
-    protected abstract void addJRTableHeader(ExportContextCSV exportContextPDF, MetaAndTableJRDataSource source, RESULTS results);
+    protected abstract void addJRTableHeader(ExportContextPDF exportContext, MetaAndTableJRDataSource source);
 
-    private void addJRTableData(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source, final RESULTS results) {
+    private void addJRTableData(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
 
         final Collection<ResultRow> rows = getRows();
 
         for (final ResultRow row : rows) {
 
-            final String[] formattedRow = formatPDFRow(exportContextPDF, results, row);
+            final String[] formattedRow = formatPDFRow(exportContext, row);
             source.addData(formattedRow);
         }
     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCommonExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCommonExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,15 +14,17 @@
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 import org.dive4elements.river.exports.AbstractExporter;
 import org.w3c.dom.Document;
 
 import au.com.bytecode.opencsv.CSVWriter;
+import net.sf.jasperreports.engine.JRException;
 
 /**
  * @author Gernot Belger
  */
-public abstract class AbstractCommonExporter<RESULTS extends AbstractCalculationResults> extends AbstractExporter {
+public abstract class AbstractCommonExporter<RESULT extends AbstractCalculationExportableResult, RESULTS extends AbstractCalculationResults<RESULT>> extends AbstractExporter {
 
     /** The log used in this exporter. */
     private final Logger log = Logger.getLogger(getClass());
@@ -34,17 +36,9 @@
 
     private RESULTS results = null;
 
-    private ExportContextPDF helper;
-
     @Override
     public void init(final String outName, final Document request, final OutputStream out, final CallContext context) {
         super.init(outName, request, out, context);
-
-        this.helper = new ExportContextPDF(context); // bleibt so asynchron zu ExportContextCSV - ist so beabsichtigt
-    }
-
-    protected final ExportContextPDF getHelper() {
-        return this.helper;
     }
 
     @Override
@@ -67,16 +61,37 @@
         return this.results;
     }
 
-    protected final AbstractCalculationResults getResults2() {
-        return this.results;
+    @Override
+    protected final void writeCSVData(final CSVWriter writer) {
+
+        final ExportContextCSV exportContext = new ExportContextCSV(this.context, writer, this.results);
+
+        doWriteCSVData(exportContext, this.results);
     }
 
-    @Override
-    protected final void writeCSVData(final CSVWriter writer) {
-        doWriteCSVData(writer, this.results);
+    protected final void doWriteCSVData(final ExportContextCSV exportContext, final RESULTS results) {
+
+        writeCSVGlobalMetadata(exportContext, results);
+
+        final RiverInfo river = results.getRiver();
+
+        final Class<?> lastResultType = null;
+
+        for (final AbstractCalculationExportableResult result : results.getResults()) {
+
+            final Class<?> resultType = result.getClass();
+            if (lastResultType == null || lastResultType != resultType) {
+                exportContext.writeBlankLine();
+                result.writeCSVHeader(exportContext, river);
+                exportContext.writeBlankLine();
+            } else
+                exportContext.writeCSVLine(new String[] { "#" });
+
+            result.writeCsv(exportContext);
+        }
     }
 
-    protected abstract void doWriteCSVData(CSVWriter writer, RESULTS results);
+    protected abstract void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final RESULTS results);
 
     /**
      * Formats header with unit and label: msg [unit] (label)
@@ -92,5 +107,35 @@
         doWritePdf(out, this.results);
     }
 
-    protected abstract void doWritePdf(OutputStream out, RESULTS results);
+    private final void doWritePdf(final OutputStream out, final RESULTS results) {
+
+        try {
+            final ExportContextPDF exportContext = new ExportContextPDF(this.context, results);
+
+            final JasperReporter reporter = new JasperReporter();
+
+            for (final RESULT result : results.getResults()) {
+
+                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
+
+                writePDFGlobalMetadata(exportContext, source);
+
+                final JasperDesigner design = result.addReport(exportContext, reporter, source);
+                configureDesign(result, design);
+            }
+
+            reporter.exportPDF(out);
+        }
+        catch (final JRException je) {
+            getLog().warn("Error generating PDF Report!", je);
+        }
+    }
+
+    /**
+     * Override to implement, does nothing by default.
+     */
+    protected void configureDesign(final RESULT result, final JasperDesigner design) {
+    }
+
+    protected abstract void writePDFGlobalMetadata(ExportContextPDF exportContext, MetaAndTableJRDataSource source);
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractExportContext.java	Fri Jun 29 14:54:40 2018 +0200
@@ -0,0 +1,85 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.common;
+
+import java.text.NumberFormat;
+
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.utils.Formatter;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public abstract class AbstractExportContext implements IExportContext {
+
+    private NumberFormat qFormat = null;
+
+    private NumberFormat flowDepthFormat = null;
+
+    private NumberFormat kmFormat = null;
+
+    /** The CallContext object. */
+    private final CallContext context;
+
+    private final AbstractCalculationResults<?> results;
+
+    public AbstractExportContext(final CallContext context, final AbstractCalculationResults<?> results) {
+        this.context = context;
+        this.results = results;
+    }
+
+    protected final CallContext getContext() {
+        return this.context;
+    }
+
+    @Override
+    public final <RESULTS extends AbstractCalculationResults<?>> RESULTS getResults() {
+        @SuppressWarnings("unchecked")
+        final RESULTS resultsCast = (RESULTS) this.results;
+        return resultsCast;
+    }
+
+    // copy from AbstractExporter TODO merge with ExportContextPDF
+    protected NumberFormat getKmFormatter() {
+
+        if (this.kmFormat == null)
+            this.kmFormat = Formatter.getWaterlevelKM(getContext());
+
+        return this.kmFormat;
+    }
+
+    public NumberFormat getQFormatter() {
+        if (this.qFormat == null)
+            this.qFormat = Formatter.getWaterlevelQ(this.context);
+
+        return this.qFormat;
+    }
+
+    public final NumberFormat getFlowDepthFormatter() {
+        if (this.flowDepthFormat == null)
+            this.flowDepthFormat = Formatter.getFlowDepth(this.context);
+
+        return this.flowDepthFormat;
+    }
+
+    protected String msg(final String key) {
+        return Resources.getMsg(this.context.getMeta(), key, key);
+    }
+
+    protected final String msg(final String key, final Object... args) {
+        return Resources.getMsg(this.context.getMeta(), key, key, args);
+    }
+
+    @Override
+    public final String formatRowValue(final ResultRow row, final IResultType type) {
+        return row.exportValue(this.context, type);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/DefaultCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -0,0 +1,27 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.common;
+
+import java.util.Collection;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class DefaultCalculationResult extends AbstractCalculationResult {
+
+    public DefaultCalculationResult(final String label, final Collection<ResultRow> rows) {
+        super(label, rows);
+        // do nothing,
+        // this class only serves as instantiable version of AbstractCalculationResult
+        // not intended for pdf/csv-export
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ExportContextCSV.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ExportContextCSV.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,7 +10,6 @@
 package org.dive4elements.river.artifacts.common;
 
 import java.text.DateFormat;
-import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -22,11 +21,9 @@
 import org.dive4elements.river.FLYS;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoI18NStrings;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
-import org.dive4elements.river.utils.Formatter;
 
 import au.com.bytecode.opencsv.CSVWriter;
 
@@ -34,7 +31,7 @@
  * @author Domenico Nardi Tironi
  *
  */
-public final class ExportContextCSV {
+public final class ExportContextCSV extends AbstractExportContext {
 
     private static final String CSV_META_HEADER_EVALUATOR = "sinfo.export.flow_depth.csv.meta.header.sounding.evaluator";
 
@@ -50,33 +47,20 @@
 
     private static final String CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL = "sinfo.export.flow_depth.csv.meta.header.sounding.elevationmodel.original";
 
-    private NumberFormat qFormat = null;
-
-    private NumberFormat flowDepthFormat = null;
-
-    private NumberFormat kmFormat = null;
-
-    /** The CallContext object. */
-    private final CallContext context;
-
     private final CSVWriter writer;
 
-    public ExportContextCSV(final CallContext context, final CSVWriter writer) {
-        this.context = context;
-        this.writer = writer;
-    }
+    private final AbstractCalculationResults<?> results;
 
-    private String msg(final String key) {
-        return Resources.getMsg(this.context.getMeta(), key, key);
-    }
+    public ExportContextCSV(final CallContext context, final CSVWriter writer, final AbstractCalculationResults<?> results) {
+        super(context, results);
 
-    public String msg(final String key, final Object... args) {
-        return Resources.getMsg(this.context.getMeta(), key, key, args);
+        this.writer = writer;
+        this.results = results;
     }
 
     public final void writeCSVMetaEntry(final String message, final Object... messageArgs) {
 
-        final CallMeta meta = this.context.getMeta();
+        final CallMeta meta = getContext().getMeta();
 
         this.writer.writeNext(new String[] { Resources.getMsg(meta, message, message, messageArgs) });
     }
@@ -101,19 +85,11 @@
         return msg(type.getCsvHeader());
     }
 
-    public String formatRowValue(final ResultRow row, final IResultType type) {
-        return row.exportValue(this.context, type);
-    }
-
-    public void addJRMetadata(final MetaAndTableJRDataSource source, final String key, final IResultType type) {
-        source.addMetaData(key, type.getPdfHeader(this.context.getMeta()));
-    }
-
-    public final void writeCSVGlobalMetadataDefaults(final AbstractCalculationResults<?> results) {
+    public final void writeCSVGlobalMetadataDefaults() {
         // TODO: results as member
-        final String calcModeLabel = results.getCalcModeLabel();
-        final RiverInfo river = results.getRiver();
-        final DoubleRange calcRange = results.getCalcRange();
+        final String calcModeLabel = this.results.getCalcModeLabel();
+        final RiverInfo river = this.results.getRiver();
+        final DoubleRange calcRange = this.results.getCalcRange();
 
         writeCSVMetaEntry(I18NStrings.CSV_META_HEADER_RESULT, msg(I18NStrings.CSV_META_HEADER_RESULT_LABEL), river.getName(), calcModeLabel);
 
@@ -121,10 +97,10 @@
         writeCSVMetaEntry(I18NStrings.CSV_META_VERSION, msg(I18NStrings.CSV_META_VERSION_LABEL), FLYS.VERSION);
 
         // "# Bearbeiter: "
-        writeCSVMetaEntry(I18NStrings.CSV_META_USER, msg(I18NStrings.CSV_META_USER_LABEL), results.getUser());
+        writeCSVMetaEntry(I18NStrings.CSV_META_USER, msg(I18NStrings.CSV_META_USER_LABEL), this.results.getUser());
 
         // "# Datum der Erstellung: "
-        final Locale locale = Resources.getLocale(this.context.getMeta());
+        final Locale locale = Resources.getLocale(getContext().getMeta());
         final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
         writeCSVMetaEntry(I18NStrings.CSV_META_CREATION, msg(I18NStrings.CSV_META_CREATION_LABEL), df.format(new Date()));
 
@@ -161,33 +137,6 @@
             writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_YEAR, Integer.toString(year));
     }
 
-    // copy from AbstractExporter TODO merge with ExportContextPDF
-    protected NumberFormat getKmFormatter() {
-
-        if (this.kmFormat == null)
-            this.kmFormat = Formatter.getWaterlevelKM(this.context);
-
-        return this.kmFormat;
-    }
-
-    public void addJRMetadata(final MetaAndTableJRDataSource source, final String key, final String msg) {
-        source.addMetaData(key, msg);
-    }
-
-    public NumberFormat getQFormatter() {
-        if (this.qFormat == null)
-            this.qFormat = Formatter.getWaterlevelQ(this.context);
-
-        return this.qFormat;
-    }
-
-    public final NumberFormat getFlowDepthFormatter() {
-        if (this.flowDepthFormat == null)
-            this.flowDepthFormat = Formatter.getFlowDepth(this.context);
-
-        return this.flowDepthFormat;
-    }
-
     /**
      * Formats header with unit: msg [unit]
      */
@@ -228,10 +177,6 @@
         return String.format("%s [%s] (%s)", msg, unit, label);
     }
 
-    public String msgPdf(final SInfoResultType type) {
-        return type.getPdfHeader(this.context.getMeta());
-    }
-
     public void writeTitleForTabs(final String tabTitleMsg, final int colSize) {
 
         final Collection<String> title = new ArrayList<>(colSize);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ExportContextPDF.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ExportContextPDF.java	Fri Jun 29 14:54:40 2018 +0200
@@ -18,96 +18,66 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.FLYS;
 import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-import org.dive4elements.river.utils.Formatter;
 
 /**
  * @author Domenico Nardi Tironi
  *
  */
-public final class ExportContextPDF {
-
-    private NumberFormat kmFormat;
+public final class ExportContextPDF extends AbstractExportContext {
 
-    /** The CallContext object. */
-    private final CallContext context;
-
-    public ExportContextPDF(final CallContext context) {
-        this.context = context;
-
+    public ExportContextPDF(final CallContext context, final AbstractCalculationResults<?> results) {
+        super(context, results);
     }
 
-    private String msg(final String key) {
-        return Resources.getMsg(this.context.getMeta(), key, key);
-    }
-
-    private String msg(final String key, final Object... args) {
-        return Resources.getMsg(this.context.getMeta(), key, key, args);
+    // TODO: rename
+    public String msgPdf(final SInfoResultType type) {
+        return type.getPdfHeader(getContext().getMeta());
     }
 
     public void addJRMetadata(final MetaAndTableJRDataSource source, final String key, final IResultType type) {
-        source.addMetaData(key, type.getPdfHeader(this.context.getMeta()));
+        source.addMetaData(key, type.getPdfHeader(getContext().getMeta()));
+    }
+
+    public void addJRMetadata(final MetaAndTableJRDataSource source, final String key, final String msg) {
+        source.addMetaData(key, msg);
     }
 
     // *** CUSTOM STUFF that is used multiple times ***///
-    public void addJRMetaDataDefaults(final MetaAndTableJRDataSource source, final AbstractCalculationResults results) {
+    public void addJRMetaDataDefaults(final MetaAndTableJRDataSource source) {
 
         source.addMetaData("header", msg(I18NStrings.CSV_META_HEADER_RESULT_LABEL));
-        source.addMetaData("calcMode", results.getCalcModeLabel());
+        source.addMetaData("calcMode", getResults().getCalcModeLabel());
 
         source.addMetaData("version_label", msg(I18NStrings.CSV_META_VERSION_LABEL));
         source.addMetaData("version", FLYS.VERSION);
 
         source.addMetaData("user_label", msg(I18NStrings.CSV_META_USER_LABEL));
-        source.addMetaData("user", results.getUser());
+        source.addMetaData("user", getResults().getUser());
 
-        final Locale locale = Resources.getLocale(this.context.getMeta());
+        final Locale locale = Resources.getLocale(getContext().getMeta());
         final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
         source.addMetaData("date_label", msg(I18NStrings.CSV_META_CREATION_LABEL));
         source.addMetaData("date", df.format(new Date()));
     }
 
-    public void addJRMetaDataUSINFO(final MetaAndTableJRDataSource source, final AbstractCalculationResults results) {
+    public void addJRMetaDataUSINFO(final MetaAndTableJRDataSource source) {
 
         /* general metadata */
-        addJRMetaDataDefaults(source, results);
+        addJRMetaDataDefaults(source);
 
-        final RiverInfo river = results.getRiver();
+        final RiverInfo river = getResults().getRiver();
         final String wstUnitName = river.getWstUnit();
 
         source.addMetaData("river_label", msg(I18NStrings.CSV_META_RIVER_LABEL));
         source.addMetaData("river", river.getName());
         source.addMetaData("river_unit", wstUnitName);
 
-        final DoubleRange calcRange = results.getCalcRange();
+        final DoubleRange calcRange = getResults().getCalcRange();
         final NumberFormat kmFormatter = getKmFormatter();
         final String rangeValue = String.format("%s - %s", kmFormatter.format(calcRange.getMinimumDouble()), kmFormatter.format(calcRange.getMaximumDouble()));
         source.addMetaData("range_label", msg(I18NStrings.CSV_META_RANGE_LABEL));
         source.addMetaData("range", rangeValue);
-
-        /* column headings */
-        // source.addMetaData("station_header", GeneralResultType.station.getPdfHeader(this.context.getMeta()));
-
-        // moved to *result
-        /* column headings */
-        // source.addMetaData("flowdepth_header", SInfoResultType.flowdepth.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("flowdepth_tkh_header", SInfoResultType.flowdepthtkh.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("tkh_header", SInfoResultType.tkh.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("waterlevel_header", SInfoResultType.waterlevel.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("discharge_header", SInfoResultType.discharge.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("waterlevel_name_header", SInfoResultType.waterlevelLabel.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("gauge_header", SInfoResultType.gaugeLabel.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("bedheight_header", SInfoResultType.meanBedHeight.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("sounding_name_header", SInfoResultType.soundingLabel.getPdfHeader(this.context.getMeta()));
-        // source.addMetaData("location_header", SInfoResultType.location.getPdfHeader(this.context.getMeta()));
-    }
-
-    // copy from AbstractExporter TODO merge with ExportContextCSV
-    protected NumberFormat getKmFormatter() {
-
-        if (this.kmFormat == null) {
-            this.kmFormat = Formatter.getWaterlevelKM(this.context);
-        }
-        return this.kmFormat;
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/IExportContext.java	Fri Jun 29 14:54:40 2018 +0200
@@ -0,0 +1,20 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.common;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public interface IExportContext {
+
+    String formatRowValue(ResultRow row, IResultType type);
+
+    <RESULTS extends AbstractCalculationResults<?>> RESULTS getResults();
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcDetailResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcDetailResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,9 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
@@ -25,7 +27,7 @@
  *
  * @author Gernot Belger
  */
-final class CollisionCalcDetailResult extends AbstractCalculationExportableResult<CollisionCalculationResults> {
+final class CollisionCalcDetailResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
     private static final String JASPER_FILE = "/jasper/templates/sinfo.collision.detail.jrxml";
@@ -35,13 +37,13 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
 
         // do nothing so far
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final int colSize = 6;
         exportContextCSV.writeTitleForTabs("sinfo.export.csv.title.collision.detail", 6); // Voraussetzung für Tabs ist, dass der Titel vor den Headern
@@ -61,30 +63,30 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
-        return formatRow(exportContextCSV, results, row);
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+        return formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextCSV, final ResultRow row) {
         /*
          * final Collection<String> lines = new ArrayList<>(6);
          * lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station));
          * return lines.toArray(new String[lines.size()]);
          */
-        return formatRow(exportContextCSV, results, row);
+        return formatRow(exportContextCSV, row);
     }
 
-    private String[] formatRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
+    private String[] formatRow(final IExportContext exportContext, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(6);
 
-        lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station));
-        lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.date));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.collisionGaugeW));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.gaugeLabel));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.discharge));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.dischargeZone));
+        lines.add(exportContext.formatRowValue(row, GeneralResultType.station));
+        lines.add(exportContext.formatRowValue(row, GeneralResultType.date));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.collisionGaugeW));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.gaugeLabel));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.discharge));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.dischargeZone));
 
         return lines.toArray(new String[lines.size()]);
     }
@@ -95,7 +97,7 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextCSV, final MetaAndTableJRDataSource source, final CollisionCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextCSV, final MetaAndTableJRDataSource source) {
 
         /* column headings */
         exportContextCSV.addJRMetadata(source, "station_header", GeneralResultType.station);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcOverviewResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcOverviewResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,6 +14,7 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
@@ -25,7 +26,7 @@
  *
  * @author Gernot Belger
  */
-final public class CollisionCalcOverviewResult extends AbstractCalculationExportableResult<CollisionCalculationResults> {
+final public class CollisionCalcOverviewResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
 
@@ -36,12 +37,12 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         // do nothing so far
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
         final int colSize = 3;
         exportContextCSV.writeTitleForTabs("sinfo.export.csv.title.collison.overview", 3); // Voraussetzung für Tabs ist, dass der Titel vor den Headern
                                                                                            // geschrieben wird.
@@ -57,21 +58,23 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
-        return formatRow(exportContextCSV, results, row);
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+        return formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
+
         final Collection<String> lines = new ArrayList<>(3);
 
-        lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.years));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.collisionCount));
+        lines.add(exportContextPDF.formatRowValue(row, GeneralResultType.station));
+        lines.add(exportContextPDF.formatRowValue(row, SInfoResultType.years));
+        lines.add(exportContextPDF.formatRowValue(row, SInfoResultType.collisionCount));
+
         return lines.toArray(new String[lines.size()]);
     }
 
-    private String[] formatRow(final ExportContextCSV exportContextCSV, final CollisionCalculationResults results, final ResultRow row) {
+    private String[] formatRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(3);
 
@@ -88,11 +91,11 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextCSV, final MetaAndTableJRDataSource source, final CollisionCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
 
         /* column headings */
-        exportContextCSV.addJRMetadata(source, "station_header", GeneralResultType.station);
-        exportContextCSV.addJRMetadata(source, "collision_years_header", SInfoResultType.years);
-        exportContextCSV.addJRMetadata(source, "collision_count_header", SInfoResultType.collisionCount);
+        exportContext.addJRMetadata(source, "station_header", GeneralResultType.station);
+        exportContext.addJRMetadata(source, "collision_years_header", SInfoResultType.years);
+        exportContext.addJRMetadata(source, "collision_count_header", SInfoResultType.collisionCount);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,7 +17,7 @@
 /**
  * @author Gernot Belger
  */
-final class CollisionCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<CollisionCalculationResults>> {
+final class CollisionCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -9,76 +9,28 @@
  */
 package org.dive4elements.river.artifacts.sinfo.collision;
 
-import java.io.OutputStream;
-
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
-import org.dive4elements.river.artifacts.common.JasperReporter;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoI18NStrings;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * @author Gernot Belger
  */
-public final class CollisionExporter extends AbstractCommonExporter<CollisionCalculationResults> {
+public final class CollisionExporter extends AbstractCommonExporter<AbstractCalculationExportableResult, CollisionCalculationResults> {
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final CollisionCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_YEARS, results.getYearsHeader());
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final CollisionCalculationResults results) {
 
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<CollisionCalculationResults> result : results.getResults()) {
+        exportContext.writeCSVGlobalMetadataDefaults();
 
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
+        exportContext.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_YEARS, results.getYearsHeader());
     }
 
     @Override
-    protected void doWritePdf(final OutputStream out, final CollisionCalculationResults results) {
-        // TODO: Move to super
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<CollisionCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
-
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
-
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
     }
-}
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -61,10 +61,9 @@
         final Collection<ResultRow> rows = new ArrayList<>();
         for (final CollisionAggregateValue value : values) {
             rows.add(ResultRow.create().putValue(GeneralResultType.station, value.getStation()) //
-                    .putValue(SInfoResultType.collisionCount, value.getCount())
-                    .putValue(SInfoResultType.collisionGaugeW, value.getGaugeW()));
+                    .putValue(SInfoResultType.collisionCount, value.getCount()).putValue(SInfoResultType.collisionGaugeW, value.getGaugeW()));
         }
-        return new CollisionQueryCalculationResult(series.getFilename(), rows);
+        return new CollisionCalcOverviewResult(series.getFilename(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.collision;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a river bed collision series
- *
- * @author Matthias Schäfer
- */
-public final class CollisionQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public CollisionQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -77,7 +77,7 @@
         final CollisionCalculationResults results = (CollisionCalculationResults) res.getData();
 
         /* add themes for chart, for each result */
-        final List<AbstractCalculationExportableResult<CollisionCalculationResults>> resultList = results.getResults();
+        final List<AbstractCalculationExportableResult> resultList = results.getResults();
         for (int index = 0; index < resultList.size(); index++) {
             if (resultList.get(index) instanceof CollisionCalcOverviewResult) {
                 final CollisionCalcOverviewResult result = (CollisionCalcOverviewResult) resultList.get(index);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/GaugeDischargeZoneFinder.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/GaugeDischargeZoneFinder.java	Fri Jun 29 14:54:40 2018 +0200
@@ -36,8 +36,7 @@
 
     private final NavigableMap<Double, MainValue> qZones;
 
-    private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht
-
+    private final String approxPrefix = "\u2248";// "ca.";
 
     /***** CONSTRUCTORS *****/
 
@@ -49,7 +48,6 @@
             this.qZones.put(Double.valueOf(mainValue.getValue().doubleValue()), mainValue);
     }
 
-
     /***** METHODS *****/
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -13,7 +13,6 @@
 import java.util.List;
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
-import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.SoilKind;
 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
@@ -24,7 +23,7 @@
  * @author Gernot Belger
  */
 
-public abstract class AbstractTkhCalculationResult<RESULTS extends AbstractCalculationResults<?>> extends AbstractCalculationExportableResult<RESULTS> {
+public abstract class AbstractTkhCalculationResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/CollisionCalcProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/CollisionCalcProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.artifacts.common.IResultType;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.collision.CollisionCalcFacet;
-import org.dive4elements.river.artifacts.sinfo.collision.CollisionCalcOverviewResult;
 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
@@ -55,6 +55,12 @@
     @Override
     protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
 
+        return buildSeriesForType(generator, bundle, theme, visible, SInfoResultType.collisionCount);
+    }
+
+    // FIXME: move to super classs and use in many implementations
+    protected final String buildSeriesForType(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible,
+            final IResultType resultType) {
         final CallContext context = generator.getContext();
         final Map<String, String> metaData = bundle.getFacet().getMetaData();
 
@@ -65,14 +71,14 @@
 
         final String facetName = bundle.getFacetName();
 
-        final CollisionCalcOverviewResult data = (CollisionCalcOverviewResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
             throw new IllegalStateException("Data is null for facet: " + facetName);
         }
 
-        final double[][] points = data.getStationPoints(SInfoResultType.collisionCount);
+        final double[][] points = data.getStationPoints(resultType);
 
         StyledSeriesBuilder.addPoints(series, points, true);
         generator.addAxisSeries(series, getAxisName(), visible);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/CollisionCountProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/CollisionCountProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -20,8 +20,8 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
 import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.collision.CollisionCalcOverviewResult;
 import org.dive4elements.river.artifacts.sinfo.collision.CollisionFacet;
-import org.dive4elements.river.artifacts.sinfo.collision.CollisionQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -66,7 +66,7 @@
 
         final String facetName = bundle.getFacetName();
 
-        final CollisionQueryCalculationResult data = (CollisionQueryCalculationResult) bundle.getData(context);
+        final CollisionCalcOverviewResult data = (CollisionCalcOverviewResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
@@ -82,8 +82,8 @@
     }
 
     public static Facet createFacet(final CallMeta callMeta, final String seriesName) {
-        return new CollisionFacet(FACET_COLLISION_COUNT,
-                Resources.getMsg(callMeta, I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, seriesName), I18N_AXIS_LABEL);
+        return new CollisionFacet(FACET_COLLISION_COUNT, Resources.getMsg(callMeta, I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, seriesName),
+                I18N_AXIS_LABEL);
     }
 
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDurationValuesFinder.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDurationValuesFinder.java	Fri Jun 29 14:54:40 2018 +0200
@@ -44,8 +44,7 @@
 
     private DoubleRange durRange;
 
-    private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht
-
+    private final String approxPrefix = "\u2248";// "ca.";
 
     /***** CONSTRUCTORS *****/
 
@@ -87,7 +86,6 @@
         }
     }
 
-
     /***** METHODS *****/
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeMainValueNameFinder.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeMainValueNameFinder.java	Fri Jun 29 14:54:40 2018 +0200
@@ -36,8 +36,7 @@
 
     private final NavigableMap<Double, MainValue> mainValues;
 
-    private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht
-
+    private final String approxPrefix = "\u2248";// "ca.";
 
     /***** CONSTRUCTORS *****/
 
@@ -54,7 +53,6 @@
         }
     }
 
-
     /***** METHODS *****/
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.InfrastructureFacet;
-import org.dive4elements.river.artifacts.sinfo.flood_duration.InfrastructureQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -65,7 +65,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final InfrastructureQueryCalculationResult data = (InfrastructureQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
@@ -81,7 +81,7 @@
     }
 
     public static Facet createFacet(final CallMeta callMeta, final String seriesName) {
-        return new InfrastructureFacet(FACET_INFRASTRUCTURE_HEIGHT,
-                Resources.getMsg(callMeta, I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, seriesName), I18N_AXIS_LABEL);
+        return new InfrastructureFacet(FACET_INFRASTRUCTURE_HEIGHT, Resources.getMsg(callMeta, I18N_SERIES_NAME_PATTERN, I18N_SERIES_NAME_PATTERN, seriesName),
+                I18N_AXIS_LABEL);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelFacet;
-import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -65,7 +65,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final PredefinedChannelQueryCalculationResult data = (PredefinedChannelQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelFacet;
-import org.dive4elements.river.artifacts.sinfo.predefinedchannel.PredefinedChannelQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -65,7 +65,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final PredefinedChannelQueryCalculationResult data = (PredefinedChannelQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolFacet;
-import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -65,7 +65,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final PredefinedDepthEvolQueryCalculationResult data = (PredefinedDepthEvolQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -19,9 +19,9 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolFacet;
-import org.dive4elements.river.artifacts.sinfo.predefineddepthevol.PredefinedDepthEvolQueryCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -65,7 +65,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final PredefinedDepthEvolQueryCalculationResult data = (PredefinedDepthEvolQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,7 +17,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.sinfo.predefinedflowdepth.PredefinedFlowDepthQueryCalculationResult;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.StyledXYSeries;
@@ -57,7 +57,7 @@
         series.putMetaData(metaData, artifact, context);
 
         final String facetName = bundle.getFacetName();
-        final PredefinedFlowDepthQueryCalculationResult data = (PredefinedFlowDepthQueryCalculationResult) bundle.getData(context);
+        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java	Fri Jun 29 14:54:40 2018 +0200
@@ -48,7 +48,7 @@
         final CallContext context = generator.getContext();
 
         final String facetName = bundle.getFacetName();
-        final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context);
+        final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context); // differs from standard!
         if (data == null) {
             // Check has been here before so we keep it for security reasons
             // this should never happen though.
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Fri Jun 29 14:54:40 2018 +0200
@@ -11,16 +11,13 @@
 
 import org.apache.commons.lang.math.DoubleRange;
 import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.WINFOArtifact;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.RiversideRadioChoice.RiversideChoiceKey;
-import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper;
 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 import org.dive4elements.river.model.River;
 import org.dive4elements.river.model.sinfo.Infrastructure;
 
@@ -44,7 +41,6 @@
         /* access input data */
         final FloodDurationAccess access = new FloodDurationAccess(sinfo);
         final River river = access.getRiver();
-        final RiverInfo riverInfo = new RiverInfo(river);
         final DoubleRange calcRange = access.getRange();
 
         final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
@@ -55,15 +51,8 @@
 
         final Calculation problems = new Calculation();
 
-        final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange);
-
-        final FloodDurationCalculationResult result = calculateResult(calcModeLabel, infrasType, riverside, calcRange, infoProvider,
+        final FloodDurationCalculationResults results = calculateResult(calcModeLabel, infrasType, riverside, calcRange, infoProvider,
                 RiversideChoiceKey.fromKey(access.getRiverside()), user, problems);
-        results.addResult(result, problems);
-
-        // Calculate the selected main values, if any
-        /* misuse winfo-artifact to calculate waterlevels in the same way */
-        final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
 
         return new CalculationResult(results, problems);
     }
@@ -71,12 +60,12 @@
     /**
      * Calculates the flood durations of the infrastructures of a km range of a river
      */
-    private FloodDurationCalculationResult calculateResult(final String calcModeLabel, final String infrastructureType, final String riverside,
+    private FloodDurationCalculationResults calculateResult(final String calcModeLabel, final String infrastructureType, final String riverside,
             final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider, final RiversideChoiceKey riversideKey, final String user,
             final Calculation problems) {
 
         final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider);
         final String label = infrastructureType + ", " + riverside;
-        return calculator.execute(problems, label, calcModeLabel, calcRange, riversideKey, user).getResult();
+        return calculator.execute(problems, label, calcModeLabel, calcRange, riversideKey, user);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,9 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
@@ -25,20 +27,18 @@
  *
  * @author Gernot Belger
  */
-final class FloodDurationCalculationResult extends AbstractCalculationExportableResult<FloodDurationCalculationResults> {
+final class FloodDurationCalculationResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
 
     private static final String JASPER_FILE = "/jasper/templates/sinfo.floodduration.jrxml";
 
-
     public FloodDurationCalculationResult(final String label, final Collection<ResultRow> rows) {
         super(label, rows);
     }
 
-
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         // TODO Metadaten der Wasserspiegellage(n) falls gewählt
         // exportContextCSV.writeCSVWaterlevelMetadata(this.wstInfo);
         // exportContextCSV.writeBlankLine();
@@ -51,7 +51,7 @@
         return JASPER_FILE;
     }
 
-    protected String[] formatRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row) {
+    protected String[] formatRow(final IExportContext exportContextCSV, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(10);
 
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(20);
 
@@ -92,20 +92,19 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row) {
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
-        return this.formatRow(exportContextCSV, results, row);
+        return this.formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final FloodDurationCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return this.formatRow(exportContextPDF, results, row);
+        return this.formatRow(exportContextPDF, row);
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source,
-            final FloodDurationCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
 
         /* column headings */
         exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -9,32 +9,18 @@
  */
 package org.dive4elements.river.artifacts.sinfo.flood_duration;
 
-import java.util.List;
-
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
  * @author Gernot Belger
  */
-final class FloodDurationCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<FloodDurationCalculationResults>> {
+final class FloodDurationCalculationResults extends AbstractCalculationResults<FloodDurationCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
     public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
         super(calcModeLabel, user, river, calcRange);
     }
-
-    /**
-     * We know that this type of results only has one result member, so we can directly access it.
-     */
-    public FloodDurationCalculationResult getResult() {
-        final List<AbstractCalculationExportableResult<FloodDurationCalculationResults>> results = getResults();
-        if (results.size() < 1)
-            return null;
-
-        return (FloodDurationCalculationResult) results.get(0);
-    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -8,18 +8,11 @@
 
 package org.dive4elements.river.artifacts.sinfo.flood_duration;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.JasperDesigner;
-import org.dive4elements.river.artifacts.common.JasperReporter;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * Generates different output formats (csv, pdf) of data that resulted from a flow depths min/max computation.
@@ -28,71 +21,26 @@
  * @author Gernot Belger
  */
 // REMARK: must be public because its registered in generators.xml
-public class FloodDurationExporter extends AbstractCommonExporter<FloodDurationCalculationResults> {
+
+public class FloodDurationExporter extends AbstractCommonExporter<FloodDurationCalculationResult, FloodDurationCalculationResults> {
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final FloodDurationCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
-
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<FloodDurationCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
-
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final FloodDurationCalculationResults results) {
+        exportContext.writeCSVGlobalMetadataDefaults();
     }
 
     @Override
-    protected void doWritePdf(final OutputStream out, final FloodDurationCalculationResults results) {
-
-        // TODO: Move to super (hier ist aber spezieller code drin...)
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<FloodDurationCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
+    }
 
-                final JasperDesigner design = result.addReport(exportContextCSV, results, reporter, source);
-                if (result instanceof FloodDurationCalculationResult) {
-                    // final int wlCount = ((FloodDurationCalculationResult) result).getWaterlevelCount();
-                    // if (wlCount == 0 || wlCount == 2) {
-                    design.removeColumn("wOpt");
-                    design.removeColumn("qOpt");
-                    design.removeColumn("bezOpt");
-                    design.removeColumn("durOpt");
-                    // }
-                }
-            }
-
-            reporter.exportPDF(out);
+    @Override
+    protected void configureDesign(final FloodDurationCalculationResult result, final JasperDesigner design) {
+        if (result instanceof FloodDurationCalculationResult) { // redundant, but type might change
+            design.removeColumn("wOpt");
+            design.removeColumn("qOpt");
+            design.removeColumn("bezOpt");
+            design.removeColumn("durOpt");
         }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
-
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -74,16 +74,17 @@
             return res;
 
         final FloodDurationCalculationResults results = (FloodDurationCalculationResults) res.getData();
-        final FloodDurationCalculationResult result = results.getResult();
-        if (result != null) {
-            // add themes for chart
-            final int index = 0;
+        final List<FloodDurationCalculationResult> resultList = results.getResults();
+        int index = 0;
+        for (final FloodDurationCalculationResult result : resultList) {
 
             facets.add(FloodDurationProcessor.createFloodDurationFacet(context, hash, this.id, result, index));
             facets.add(FloodDurationProcessor.createMainValueDurationFacet(context, hash, this.id, result, index));
 
             facets.add(new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id));
             facets.add(new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id));
+
+            index++;
         }
 
         final Calculation report = res.getReport();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/InfrastructureFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/InfrastructureFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,6 +17,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.common.DefaultCalculationResult;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.BlackboardDataFacet;
@@ -63,7 +64,7 @@
             rows.add(ResultRow.create().putValue(GeneralResultType.station, value.getStation()) //
                     .putValue(SInfoResultType.infrastructureHeight, value.getHeight()));
         }
-        return new InfrastructureQueryCalculationResult(series.getFilename(), rows);
+        return new DefaultCalculationResult(series.getFilename(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/InfrastructureQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.flood_duration;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a river infrastructure series
- *
- * @author Matthias Schäfer
- */
-public final class InfrastructureQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public InfrastructureQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -13,7 +13,9 @@
 import java.util.Collection;
 
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult;
@@ -28,7 +30,7 @@
  * @author Gernot Belger
  */
 
-final class FlowDepthCalculationResult extends AbstractTkhCalculationResult<FlowDepthCalculationResults> {
+final class FlowDepthCalculationResult extends AbstractTkhCalculationResult {
 
     private static final long serialVersionUID = 1L;
 
@@ -53,7 +55,7 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final FlowDepthCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
         // getLog().info("FlowDepthExporter.writeCSVHeader");
 
         final Collection<String> header = new ArrayList<>(11);
@@ -79,7 +81,7 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FlowDepthCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
 
         exportContextCSV.writeCSVSoundingMetadata(this.sounding);
 
@@ -97,18 +99,18 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final FlowDepthCalculationResults results, final ResultRow row) {
-        return formatRow(ExportMode.csv, exportContextCSV, results, row);
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+        return formatRow(ExportMode.csv, exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final FlowDepthCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return formatRow(ExportMode.pdf, exportContextPDF, results, row);
+        return formatRow(ExportMode.pdf, exportContextPDF, row);
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source, final FlowDepthCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
 
         /* column headings */
         exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
@@ -124,25 +126,26 @@
         exportContextPDF.addJRMetadata(source, "location_header", SInfoResultType.location);
     }
 
-    private String[] formatRow(final ExportMode mode, final ExportContextCSV exportContextCSV, final FlowDepthCalculationResults results, final ResultRow row) {
+    private String[] formatRow(final ExportMode mode, final IExportContext exportContext, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(11);
 
-        lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepth));
+        lines.add(exportContext.formatRowValue(row, GeneralResultType.station));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepth));
+        final FlowDepthCalculationResults results = exportContext.getResults();
 
         if (mode == ExportMode.pdf || results.isUseTkh()) {
-            lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepthtkh));
-            lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.tkh));
+            lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepthtkh));
+            lines.add(exportContext.formatRowValue(row, SInfoResultType.tkh));
         }
 
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevel));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.discharge));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevelLabel));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.gaugeLabel));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.meanBedHeight));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.soundingLabel));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.location));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.waterlevel));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.discharge));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.waterlevelLabel));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.gaugeLabel));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.meanBedHeight));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.soundingLabel));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.location));
 
         return lines.toArray(new String[lines.size()]);
     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,7 +10,6 @@
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
@@ -18,7 +17,7 @@
  * @author Gernot Belger
  */
 
-final class FlowDepthCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<FlowDepthCalculationResults>> {
+final class FlowDepthCalculationResults extends AbstractCalculationResults<FlowDepthCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -8,18 +8,11 @@
 
 package org.dive4elements.river.artifacts.sinfo.flowdepth;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.JasperDesigner;
-import org.dive4elements.river.artifacts.common.JasperReporter;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * Generates different output formats (csv, pdf) of data that resulted from a flow depths min/max computation.
@@ -28,67 +21,25 @@
  * @author Gernot Belger
  */
 // REMARK: must be public because its registered in generators.xml
-public class FlowDepthExporter extends AbstractCommonExporter<FlowDepthCalculationResults> {
+public class FlowDepthExporter extends AbstractCommonExporter<FlowDepthCalculationResult, FlowDepthCalculationResults> {
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final FlowDepthCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
-
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<FlowDepthCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final FlowDepthCalculationResults results) {
+        exportContext.writeCSVGlobalMetadataDefaults();
     }
 
     @Override
-    protected void doWritePdf(final OutputStream out, final FlowDepthCalculationResults results) {
-
-        // TODO: Move to super? Maybe not, hier gibt es unterschiede -> design remove columns
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<FlowDepthCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
-
-                final JasperDesigner design = result.addReport(exportContextCSV, results, reporter, source);
-                if (result instanceof FlowDepthCalculationResult) {
-                    if (!((FlowDepthCalculationResult) result).hasTkh()) {
-                        design.removeColumn("tkh");
-                        design.removeColumn("flowdepthtkh");
-                    }
-                }
-                reporter.exportPDF(out);
-            }
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
-
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
     }
 
+    @Override
+    protected final void configureDesign(final FlowDepthCalculationResult result, final JasperDesigner design) {
+
+        if (result instanceof FlowDepthCalculationResult)
+            if (!result.hasTkh()) {
+                design.removeColumn("tkh");
+                design.removeColumn("flowdepthtkh");
+            }
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,6 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DataFacet;
@@ -77,10 +76,10 @@
         final FlowDepthCalculationResults results = (FlowDepthCalculationResults) res.getData();
 
         /* add themes for chart, for each result */
-        final List<AbstractCalculationExportableResult<FlowDepthCalculationResults>> resultList = results.getResults();
+        final List<FlowDepthCalculationResult> resultList = results.getResults();
         for (int index = 0; index < resultList.size(); index++) {
 
-            final FlowDepthCalculationResult result = (FlowDepthCalculationResult) resultList.get(index);
+            final FlowDepthCalculationResult result = resultList.get(index);
 
             /* filtered (zoom dependent mean) flow depth */
             facets.add(FlowDepthProcessor.createFlowDepthFilteredFacet(context, hash, this.id, result, index));
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,9 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
@@ -27,7 +29,7 @@
  *
  * @author Gernot Belger
  */
-final class FlowDepthDevelopmentCalculationResult extends AbstractCalculationExportableResult<FlowDepthDevelopmentCalculationResults> {
+final class FlowDepthDevelopmentCalculationResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
 
@@ -109,7 +111,7 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FlowDepthDevelopmentCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
 
         exportContextCSV.writeCSVSoundingMetadata(getCurrentSounding(), CSV_META_HEADER_SOUNDING_CURRENT);
         exportContextCSV.writeBlankLine();
@@ -127,24 +129,24 @@
         return JASPER_FILE;
     }
 
-    protected String[] formatRow(final ExportContextCSV exportContextCSV, final FlowDepthDevelopmentCalculationResults results, final ResultRow row) {
+    protected String[] formatRow(final IExportContext exportContext, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(10);
 
-        lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepthDevelopment));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepthDevelopmentPerYear));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevelDifference));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.bedHeightDifference));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepthCurrent));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.flowdepthHistorical));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.location));
+        lines.add(exportContext.formatRowValue(row, GeneralResultType.station));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepthDevelopment));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepthDevelopmentPerYear));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.waterlevelDifference));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.bedHeightDifference));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepthCurrent));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.flowdepthHistorical));
+        lines.add(exportContext.formatRowValue(row, SInfoResultType.location));
 
         return lines.toArray(new String[lines.size()]);
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final FlowDepthDevelopmentCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(11);
 
@@ -162,20 +164,19 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final FlowDepthDevelopmentCalculationResults results, final ResultRow row) {
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
-        return this.formatRow(exportContextCSV, results, row);
+        return this.formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final FlowDepthDevelopmentCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return this.formatRow(exportContextPDF, results, row);
+        return this.formatRow(exportContextPDF, row);
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source,
-            final FlowDepthDevelopmentCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
         /* column headings */
         exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
         exportContextPDF.addJRMetadata(source, "flowdepthdevelopment_header", SInfoResultType.flowdepthDevelopment);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -12,14 +12,13 @@
 import java.util.List;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
  * @author Gernot Belger
  */
-final class FlowDepthDevelopmentCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<FlowDepthDevelopmentCalculationResults>> {
+final class FlowDepthDevelopmentCalculationResults extends AbstractCalculationResults<FlowDepthDevelopmentCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
@@ -31,10 +30,10 @@
      * We know that this type of results only has one result member, so we can directly access it.
      */
     public FlowDepthDevelopmentCalculationResult getResult() {
-        final List<AbstractCalculationExportableResult<FlowDepthDevelopmentCalculationResults>> results = getResults();
+        final List<FlowDepthDevelopmentCalculationResult> results = getResults();
         if (results.size() < 1)
             return null;
 
-        return (FlowDepthDevelopmentCalculationResult) results.get(0);
+        return results.get(0);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -8,18 +8,12 @@
 
 package org.dive4elements.river.artifacts.sinfo.flowdepthdev;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
-import org.dive4elements.river.artifacts.common.JasperReporter;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
+import org.dive4elements.river.artifacts.common.JasperDesigner;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation.
@@ -28,63 +22,25 @@
  * @author Gernot Belger
  */
 // REMARK: must be public because its registered in generators.xml
-public class FlowDepthDevelopmentExporter extends AbstractCommonExporter<FlowDepthDevelopmentCalculationResults> {
+public class FlowDepthDevelopmentExporter extends AbstractCommonExporter<FlowDepthDevelopmentCalculationResult, FlowDepthDevelopmentCalculationResults> {
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final FlowDepthDevelopmentCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final FlowDepthDevelopmentCalculationResults results) {
+        exportContext.writeCSVGlobalMetadataDefaults();
 
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<FlowDepthDevelopmentCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
     }
 
     @Override
-    protected void doWritePdf(final OutputStream out, final FlowDepthDevelopmentCalculationResults results) {
-        // TODO: Move to super //2 lines different
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<FlowDepthDevelopmentCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
+        source.addMetaData("flowdepthdevelopment_header_label", SInfoResultType.flowdepthDevelopment.getCsvHeader(this.context.getMeta()));// (this.context.getMeta()));
 
-                // move somewhere? global meta
-                source.addMetaData("flowdepthdevelopment", result.getLabel());
-                source.addMetaData("flowdepthdevelopment_header_label", SInfoResultType.flowdepthDevelopment.getCsvHeader(this.context.getMeta()));// (this.context.getMeta()));
+    }
 
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
-
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
+    @Override
+    protected void configureDesign(final FlowDepthDevelopmentCalculationResult result, final JasperDesigner design) {
+        if (result instanceof FlowDepthDevelopmentCalculationResult) { // redundant, but type might change
+            design.getSource().addMetaData("flowdepthdevelopment", result.getLabel()); // globalMeta? wrong place. only one result expected, so it works
         }
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,9 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
@@ -27,7 +29,7 @@
  *
  * @author Gernot Belger
  */
-final class FlowDepthMinMaxCalculationResult extends AbstractCalculationExportableResult<FlowDepthMinMaxCalculationResults> {
+final class FlowDepthMinMaxCalculationResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
     private static final String JASPER_FILE = "/jasper/templates/sinfo.flowdepthminmax.jrxml";
@@ -46,7 +48,7 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final FlowDepthMinMaxCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(11);
 
@@ -66,7 +68,7 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FlowDepthMinMaxCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
 
         exportContextCSV.writeCSVSoundingMetadata(this.sounding);
         exportContextCSV.writeBlankLine();
@@ -77,15 +79,15 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final FlowDepthMinMaxCalculationResults results, final ResultRow row) {
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
-        return formatRow(exportContextCSV, results, row);
+        return formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final FlowDepthMinMaxCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return formatRow(exportContextPDF, results, row);
+        return formatRow(exportContextPDF, row);
     }
 
     @Override
@@ -94,8 +96,7 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source,
-            final FlowDepthMinMaxCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
 
         /* column headings */
         exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
@@ -111,7 +112,7 @@
 
     }
 
-    protected String[] formatRow(final ExportContextCSV exportContextCSV, final FlowDepthMinMaxCalculationResults results, final ResultRow row) {
+    protected String[] formatRow(final IExportContext exportContextCSV, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(10);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,14 +10,13 @@
 package org.dive4elements.river.artifacts.sinfo.flowdepthminmax;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
  * @author Gernot Belger
  */
-final class FlowDepthMinMaxCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<FlowDepthMinMaxCalculationResults>> {
+final class FlowDepthMinMaxCalculationResults extends AbstractCalculationResults<FlowDepthMinMaxCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -8,17 +8,10 @@
 
 package org.dive4elements.river.artifacts.sinfo.flowdepthminmax;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
-import org.dive4elements.river.artifacts.common.JasperReporter;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation.
@@ -27,60 +20,16 @@
  * @author Gernot Belger
  */
 // REMARK: must be public because its registered in generators.xml
-public class FlowDepthMinMaxExporter extends AbstractCommonExporter<FlowDepthMinMaxCalculationResults> {
+public class FlowDepthMinMaxExporter extends AbstractCommonExporter<FlowDepthMinMaxCalculationResult, FlowDepthMinMaxCalculationResults> {
 
     @Override
-    protected void doWritePdf(final OutputStream out, final FlowDepthMinMaxCalculationResults results) {
-        // TODO: Move to super
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final FlowDepthMinMaxCalculationResults results) {
+        exportContext.writeCSVGlobalMetadataDefaults();
 
-            for (final AbstractCalculationExportableResult<FlowDepthMinMaxCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
-
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
-
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
     }
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final FlowDepthMinMaxCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
-
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<FlowDepthMinMaxCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
-
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,6 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DataFacet;
@@ -77,10 +76,10 @@
         final FlowDepthMinMaxCalculationResults results = (FlowDepthMinMaxCalculationResults) res.getData();
 
         /* add themes for chart, for each result */
-        final List<AbstractCalculationExportableResult<FlowDepthMinMaxCalculationResults>> resultList = results.getResults();
+        final List<FlowDepthMinMaxCalculationResult> resultList = results.getResults();
         for (int index = 0; index < resultList.size(); index++) {
 
-            final FlowDepthMinMaxCalculationResult result = (FlowDepthMinMaxCalculationResult) resultList.get(index);
+            final FlowDepthMinMaxCalculationResult result = resultList.get(index);
 
             /* filtered (zoom dependent mean) flow depth */
             facets.add(FlowDepthProcessor.createFlowDepthMinFilteredFacet(context, hash, this.id, result, index));
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedchannel/PredefinedChannelFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedchannel/PredefinedChannelFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,6 +17,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.common.DefaultCalculationResult;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.BlackboardDataFacet;
@@ -64,7 +65,7 @@
                     .putValue(SInfoResultType.channelWidth, value.getWidth()) //
                     .putValue(SInfoResultType.channelDepth, value.getDepth()));
         }
-        return new PredefinedChannelQueryCalculationResult(series.getFilename(), rows);
+        return new DefaultCalculationResult(series.getFilename(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedchannel/PredefinedChannelQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.predefinedchannel;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a river channel width series
- *
- * @author Matthias Schäfer
- */
-public final class PredefinedChannelQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public PredefinedChannelQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefineddepthevol/PredefinedDepthEvolFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefineddepthevol/PredefinedDepthEvolFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,6 +17,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.common.DefaultCalculationResult;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.BlackboardDataFacet;
@@ -64,7 +65,7 @@
                     .putValue(SInfoResultType.flowdepthDevelopment, value.getTotalChangeCm()) //
                     .putValue(SInfoResultType.flowdepthDevelopmentPerYear, value.getPerYearChangeCm()));
         }
-        return new PredefinedDepthEvolQueryCalculationResult(series.getFilename(), rows);
+        return new DefaultCalculationResult(series.getFilename(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefineddepthevol/PredefinedDepthEvolQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.predefineddepthevol;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a depth evolution series
- *
- * @author Matthias Schäfer
- */
-public final class PredefinedDepthEvolQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public PredefinedDepthEvolQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedflowdepth/PredefinedFlowDepthFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedflowdepth/PredefinedFlowDepthFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,6 +17,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.common.DefaultCalculationResult;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.BlackboardDataFacet;
@@ -63,7 +64,7 @@
             rows.add(ResultRow.create().putValue(GeneralResultType.station, value.getStation()) //
                     .putValue(SInfoResultType.flowdepth, value.getDepth()));
         }
-        return new PredefinedFlowDepthQueryCalculationResult(series.getName(), rows);
+        return new DefaultCalculationResult(series.getName(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedflowdepth/PredefinedFlowDepthQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.predefinedflowdepth;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a tkh series
- *
- * @author Matthias Schäfer
- */
-public final class PredefinedFlowDepthQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public PredefinedFlowDepthQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedtkh/PredefinedTkhFacet.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedtkh/PredefinedTkhFacet.java	Fri Jun 29 14:54:40 2018 +0200
@@ -17,6 +17,7 @@
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.common.DefaultCalculationResult;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.BlackboardDataFacet;
@@ -72,15 +73,14 @@
             if (soilKindFinder != null) {
                 bedMobility = soilKindFinder.findSoilKind(tkhValue.getStation().doubleValue());
                 row.putValue(SInfoResultType.soilkind, bedMobility);
-            }
-            else
+            } else
                 row.putValue(SInfoResultType.soilkind, null);
             row.putValue(SInfoResultType.tkh, tkhValue.getTkhCm());
             row.putValue(SInfoResultType.tkhup, tkhValue.getTkhUpCm(bedMobility == SoilKind.mobil));
             row.putValue(SInfoResultType.tkhdown, tkhValue.getTkhDownCm(bedMobility == SoilKind.mobil));
             rows.add(row);
         }
-        return new PredefinedTkhQueryCalculationResult(series.getName(), rows);
+        return new DefaultCalculationResult(series.getName(), rows);// new PredefinedTkhQueryCalculationResult(series.getName(), rows);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/predefinedtkh/PredefinedTkhQueryCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.sinfo.predefinedtkh;
-
-import java.util.Collection;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
-import org.dive4elements.river.artifacts.common.ResultRow;
-
-/**
- * Contains the results of a database query of a tkh series
- *
- * @author Matthias Schäfer
- */
-class PredefinedTkhQueryCalculationResult extends AbstractCalculationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    public PredefinedTkhQueryCalculationResult(final String label, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -13,7 +13,9 @@
 import java.util.Collection;
 
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult;
@@ -26,7 +28,7 @@
  *
  * @author Gernot Belger
  */
-final class TkhCalculationResult extends AbstractTkhCalculationResult<TkhCalculationResults> {
+final class TkhCalculationResult extends AbstractTkhCalculationResult {
 
     private static final long serialVersionUID = 1L;
     private static final String JASPER_FILE = "/jasper/templates/sinfo.tkh.jrxml";
@@ -41,44 +43,45 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final TkhCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContext, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(11);
 
-        header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station));
-        header.add(exportContextCSV.msgUnitCSV(SInfoResultType.tkh));
-        header.add(exportContextCSV.formatCsvHeader(SInfoResultType.soilkind));
-        header.add(exportContextCSV.msgUnitCSV(SInfoResultType.meanBedHeight, river.getWstUnit()));
-        header.add(exportContextCSV.msgUnitCSV(SInfoResultType.waterlevel, river.getWstUnit()));
-        header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge));
+        header.add(exportContext.formatCsvHeader(GeneralResultType.station));
+        header.add(exportContext.msgUnitCSV(SInfoResultType.tkh));
+        header.add(exportContext.formatCsvHeader(SInfoResultType.soilkind));
+        header.add(exportContext.msgUnitCSV(SInfoResultType.meanBedHeight, river.getWstUnit()));
+        header.add(exportContext.msgUnitCSV(SInfoResultType.waterlevel, river.getWstUnit()));
+        header.add(exportContext.msgUnitCSV(SInfoResultType.discharge));
 
+        final TkhCalculationResults results = exportContext.getResults();
         final String descriptionHeader = results.getDescriptionHeader();
         if (descriptionHeader != null)
             header.add(descriptionHeader);
 
-        header.add(exportContextCSV.formatCsvHeader(SInfoResultType.gaugeLabel));
-        header.add(exportContextCSV.formatCsvHeader(SInfoResultType.location));
+        header.add(exportContext.formatCsvHeader(SInfoResultType.gaugeLabel));
+        header.add(exportContext.formatCsvHeader(SInfoResultType.location));
 
-        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
+        exportContext.writeCSVLine(header.toArray(new String[header.size()]));
 
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final TkhCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         exportContextCSV.writeCSVWaterlevelMetadata(super.getWst());// TODO: move to super
         exportContextCSV.writeBlankLine();
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final TkhCalculationResults results, final ResultRow row) {
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
-        return this.formatRow(exportContextCSV, results, row, ExportMode.csv);
+        return this.formatRow(exportContextCSV, row, ExportMode.csv);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final TkhCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContext, final ResultRow row) {
 
-        return this.formatRow(exportContextPDF, results, row, ExportMode.pdf);
+        return this.formatRow(exportContext, row, ExportMode.pdf);
     }
 
     @Override
@@ -87,27 +90,30 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source, final TkhCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
         /* column headings */
-        exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
-        exportContextPDF.addJRMetadata(source, "tkh_header", SInfoResultType.tkh);
-        exportContextPDF.addJRMetadata(source, "tkhkind_header", SInfoResultType.soilkind);
-        exportContextPDF.addJRMetadata(source, "bedheight_header", SInfoResultType.meanBedHeight);
-        exportContextPDF.addJRMetadata(source, "waterlevel_header", SInfoResultType.waterlevel);
-        exportContextPDF.addJRMetadata(source, "discharge_header", SInfoResultType.discharge);
+        exportContext.addJRMetadata(source, "station_header", GeneralResultType.station);
+        exportContext.addJRMetadata(source, "tkh_header", SInfoResultType.tkh);
+        exportContext.addJRMetadata(source, "tkhkind_header", SInfoResultType.soilkind);
+        exportContext.addJRMetadata(source, "bedheight_header", SInfoResultType.meanBedHeight);
+        exportContext.addJRMetadata(source, "waterlevel_header", SInfoResultType.waterlevel);
+        exportContext.addJRMetadata(source, "discharge_header", SInfoResultType.discharge);
 
         // REMARK: actually the column makes no sense if description header is null. But (software symmetry...) WINFO also
         // writes an empty column into the pdf in that case (most probably to avoid the need for two jasper templates).
+
+        final TkhCalculationResults results = exportContext.getResults();
         final String descriptionHeader = results.getDescriptionHeader();
-        final String waterlevelNameHeader = descriptionHeader == null ? exportContextPDF.msgPdf(SInfoResultType.waterlevelLabel) : descriptionHeader;
-        exportContextPDF.addJRMetadata(source, "waterlevel_name_header", waterlevelNameHeader);
 
-        exportContextPDF.addJRMetadata(source, "gauge_header", SInfoResultType.gaugeLabel);
-        exportContextPDF.addJRMetadata(source, "location_header", SInfoResultType.location);
+        final String waterlevelNameHeader = descriptionHeader == null ? exportContext.msgPdf(SInfoResultType.waterlevelLabel) : descriptionHeader;
+        exportContext.addJRMetadata(source, "waterlevel_name_header", waterlevelNameHeader);
+
+        exportContext.addJRMetadata(source, "gauge_header", SInfoResultType.gaugeLabel);
+        exportContext.addJRMetadata(source, "location_header", SInfoResultType.location);
 
     }
 
-    private String[] formatRow(final ExportContextCSV exportContext, final TkhCalculationResults results, final ResultRow row, final ExportMode mode) {
+    private String[] formatRow(final IExportContext exportContext, final ResultRow row, final ExportMode mode) {
 
         final Collection<String> lines = new ArrayList<>(11);
 
@@ -119,7 +125,9 @@
         lines.add(exportContext.formatRowValue(row, SInfoResultType.discharge));
 
         // REMARK: always export this column in pdf-mode, because WInfo also does it (no need for two jasper-templates).
-        if (results.getDescriptionHeader() != null || mode == ExportMode.pdf)
+        final TkhCalculationResults results = exportContext.getResults();
+        final String descriptionHeader = results.getDescriptionHeader();
+        if (descriptionHeader != null || mode == ExportMode.pdf)
             lines.add(exportContext.formatRowValue(row, SInfoResultType.waterlevelLabel));
 
         lines.add(exportContext.formatRowValue(row, SInfoResultType.gaugeLabel));
@@ -127,5 +135,4 @@
 
         return lines.toArray(new String[lines.size()]);
     }
-
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,14 +10,13 @@
 package org.dive4elements.river.artifacts.sinfo.tkhstate;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
  * @author Gernot Belger
  */
-final class TkhCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<TkhCalculationResults>> {
+final class TkhCalculationResults extends AbstractCalculationResults<TkhCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -8,17 +8,10 @@
 
 package org.dive4elements.river.artifacts.sinfo.tkhstate;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
-import org.dive4elements.river.artifacts.common.JasperReporter;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * Generates different output formats (csv, pdf) of data that resulted from a tkh computation.
@@ -26,67 +19,25 @@
  * @author Gernot Belger
  */
 // REMARK: must be public because its registered in generators.xml
-public class TkhExporter extends AbstractCommonExporter<TkhCalculationResults> {
+public class TkhExporter extends AbstractCommonExporter<TkhCalculationResult, TkhCalculationResults> {
 
     private static final String CSV_META_CALCULATION_FORMULA = "sinfo.export.tkh.calculation.formula";
 
     @Override
-    protected void doWritePdf(final OutputStream out, final TkhCalculationResults results) {
-        // TODO: Move to super
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<TkhCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final TkhCalculationResults results) {
 
-                source.addMetaData("calculation_label", msg("sinfo.export.flow_depth.pdf.meta.calculation.label"));
-                source.addMetaData("calculation_name", msg("sinfo.export.flow_depth.pdf.meta.calculation.name"));
+        /* write as csv */
+        exportContext.writeCSVGlobalMetadataDefaults(); // ggf auslagern innerhalb dieser Klasse
 
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
-
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
+        // "# Berechnungsgrundlage: Gleichung nach GILL (1971)"
+        exportContext.writeCSVMetaEntry(CSV_META_CALCULATION_FORMULA);
     }
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final TkhCalculationResults results) {
-        // TODO: Diesen Ablauf in super? _WINZIGE ABWEICHUNG vom Standard...
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // "# Berechnungsgrundlage: Gleichung nach GILL (1971)"
-        exportContextCSV.writeCSVMetaEntry(CSV_META_CALCULATION_FORMULA);
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+    protected final void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
 
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<TkhCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
+        source.addMetaData("calculation_label", msg("sinfo.export.flow_depth.pdf.meta.calculation.label"));
+        source.addMetaData("calculation_name", msg("sinfo.export.flow_depth.pdf.meta.calculation.name"));
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,6 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DataFacet;
@@ -81,10 +80,10 @@
         final TkhCalculationResults results = (TkhCalculationResults) res.getData();
 
         /* add themes for chart, for each result */
-        final List<AbstractCalculationExportableResult<TkhCalculationResults>> resultList = results.getResults();
+        final List<TkhCalculationResult> resultList = results.getResults();
         for (int index = 0; index < resultList.size(); index++) {
 
-            final TkhCalculationResult result = (TkhCalculationResult) resultList.get(index);
+            final TkhCalculationResult result = resultList.get(index);
 
             facets.add(TkhProcessor.createTkhFacet(context, hash, this.id, result, index));
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,7 +14,9 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.GeneralResultType;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
@@ -24,7 +26,7 @@
 /**
  * @author Domenico Nardi Tironi
  */
-final class SalixLineCalculationResult extends AbstractCalculationExportableResult<SalixLineCalculationResults> {
+final class SalixLineCalculationResult extends AbstractCalculationExportableResult {
 
     private static final long serialVersionUID = 1L;
     private static final String JASPER_FILE = "/jasper/templates/uinfo.salixline.jrxml";
@@ -34,7 +36,7 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final SalixLineCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(4);
 
@@ -51,9 +53,9 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final SalixLineCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         writeRegionalEffectsCSVMetadata(exportContextCSV);
-        exportContextCSV.writeBlankLine();// writer.writeNext(new String[] { "" }); // break line
+        exportContextCSV.writeBlankLine();
         writeExtendedRegionalEffectsCSVMetadata(exportContextCSV);
         exportContextCSV.writeBlankLine();
         writeHistoricalViewCSVMetadata(exportContextCSV);
@@ -62,15 +64,15 @@
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final SalixLineCalculationResults results, final ResultRow row) {
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
 
-        return formatRow(exportContextCSV, results, row);
+        return formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final SalixLineCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return formatRow(exportContextPDF, results, row);
+        return formatRow(exportContextPDF, row);
     }
 
     @Override
@@ -80,7 +82,7 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source, final SalixLineCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
 
         /* additional column headings */
         exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
@@ -93,7 +95,7 @@
 
     }
 
-    private String[] formatRow(final ExportContextCSV context, final SalixLineCalculationResults results, final ResultRow row) {
+    private String[] formatRow(final IExportContext context, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(3);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,7 +10,6 @@
 package org.dive4elements.river.artifacts.uinfo.salix;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
@@ -18,7 +17,7 @@
  * @author Domenico Nardi Tironi
  *
  */
-final class SalixLineCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<SalixLineCalculationResults>> {
+final class SalixLineCalculationResults extends AbstractCalculationResults<SalixLineCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -9,60 +9,24 @@
  */
 package org.dive4elements.river.artifacts.uinfo.salix;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.I18NStrings;
-import org.dive4elements.river.artifacts.common.JasperReporter;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * @author Domenico Nardi Tironi
  *
  */
-public class SalixLineExporter extends AbstractCommonExporter<SalixLineCalculationResults> {
+public class SalixLineExporter extends AbstractCommonExporter<SalixLineCalculationResult, SalixLineCalculationResults> {
 
     @Override
-    protected void doWritePdf(final OutputStream out, final SalixLineCalculationResults results) {
-        // TODO: Move to super
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
-
-            for (final AbstractCalculationExportableResult<SalixLineCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
-
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContextCSV, final SalixLineCalculationResults results) {
+        /* write as csv */
+        exportContextCSV.writeCSVGlobalMetadataDefaults(); // ggf auslagern innerhalb dieser Klasse
 
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
-    }
-
-    @Override
-    protected void doWriteCSVData(final CSVWriter writer, final SalixLineCalculationResults results) {
-        // TODO: Diesen Ablauf in super? - ist etwas anders bei den globalen metadaten
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+        // break line ?
 
         // "# Höhensystem des Flusses: "
         exportContextCSV.writeCSVMetaEntry(I18NStrings.CSV_META_HEIGHT_UNIT_RIVER, results.getRiver().getWstUnit());
@@ -79,22 +43,11 @@
         // if (year > 0)
         exportContextCSV.writeCSVMetaEntry("uinfo.export.salix_line.csv.meta.header.waterlevel.year", "Integer.toString(year)");
 
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<SalixLineCalculationResults> result : results.getResults()) {
+    }
 
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
+    @Override
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
     }
 
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -15,7 +15,6 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DataFacet;
@@ -78,7 +77,7 @@
 
         final SalixLineCalculationResults results = (SalixLineCalculationResults) res.getData();
 
-        final List<AbstractCalculationExportableResult<SalixLineCalculationResults>> resultList = results.getResults();
+        final List<SalixLineCalculationResult> resultList = results.getResults();
 
         if (!resultList.isEmpty()) {
             final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCalculationResult.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCalculationResult.java	Fri Jun 29 14:54:40 2018 +0200
@@ -14,6 +14,8 @@
 
 import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
+import org.dive4elements.river.artifacts.common.IExportContext;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
@@ -22,7 +24,7 @@
 /**
  * @author Domenico Nardi Tironi
  */
-final class VegetationZonesCalculationResult extends AbstractCalculationExportableResult<VegetationZonesCalculationResults> {
+final class VegetationZonesCalculationResult extends AbstractCalculationExportableResult {
     private static final long serialVersionUID = 1L;
 
     private static final String JASPER_FILE = "/jasper/templates/uinfo.vegetationzones.jrxml";
@@ -32,7 +34,7 @@
     }
 
     @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final VegetationZonesCalculationResults results, final RiverInfo river) {
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
 
         final Collection<String> header = new ArrayList<>(11);
 
@@ -44,20 +46,20 @@
     }
 
     @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final VegetationZonesCalculationResults results) {
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
         // no metadata
 
     }
 
     @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final VegetationZonesCalculationResults results, final ResultRow row) {
-        return formatRow(exportContextCSV, results, row);
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+        return formatRow(exportContextCSV, row);
     }
 
     @Override
-    protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final VegetationZonesCalculationResults results, final ResultRow row) {
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
 
-        return formatRow(exportContextPDF, results, row);
+        return formatRow(exportContextPDF, row);
     }
 
     @Override
@@ -67,8 +69,7 @@
     }
 
     @Override
-    protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source,
-            final VegetationZonesCalculationResults results) {
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
         /* additional column headings */
         exportContextPDF.addJRMetadata(source, "veg_name", UInfoResultType.vegname);
         exportContextPDF.addJRMetadata(source, "veg_dauervon", UInfoResultType.vegdauervon);
@@ -76,7 +77,7 @@
 
     }
 
-    protected String[] formatRow(final ExportContextCSV context, final VegetationZonesCalculationResults results, final ResultRow row) {
+    protected String[] formatRow(final IExportContext context, final ResultRow row) {
 
         final Collection<String> lines = new ArrayList<>(11);
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCalculationResults.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCalculationResults.java	Fri Jun 29 14:54:40 2018 +0200
@@ -10,7 +10,6 @@
 package org.dive4elements.river.artifacts.uinfo.vegetationzones;
 
 import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
@@ -18,7 +17,7 @@
  * @author Domenico Nardi Tironi
  *
  */
-final class VegetationZonesCalculationResults extends AbstractCalculationResults<AbstractCalculationExportableResult<VegetationZonesCalculationResults>> {
+final class VegetationZonesCalculationResults extends AbstractCalculationResults<VegetationZonesCalculationResult> {
 
     private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesExporter.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesExporter.java	Fri Jun 29 14:54:40 2018 +0200
@@ -9,75 +9,25 @@
  */
 package org.dive4elements.river.artifacts.uinfo.vegetationzones;
 
-import java.io.OutputStream;
-
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.common.AbstractCommonExporter;
 import org.dive4elements.river.artifacts.common.ExportContextCSV;
-import org.dive4elements.river.artifacts.common.JasperReporter;
+import org.dive4elements.river.artifacts.common.ExportContextPDF;
 import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
-import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
-
-import au.com.bytecode.opencsv.CSVWriter;
-import net.sf.jasperreports.engine.JRException;
 
 /**
  * @author Domenico Nardi Tironi
  *
  */
-public class VegetationZonesExporter extends AbstractCommonExporter<VegetationZonesCalculationResults> {
+public class VegetationZonesExporter extends AbstractCommonExporter<VegetationZonesCalculationResult, VegetationZonesCalculationResults> {
 
     @Override
-    protected void doWritePdf(final OutputStream out, final VegetationZonesCalculationResults results) {
-        // TODO: Move to super
-        try {
-            final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null);
-
-            final JasperReporter reporter = new JasperReporter();
+    protected void writeCSVGlobalMetadata(final ExportContextCSV exportContext, final VegetationZonesCalculationResults results) {
+        exportContext.writeCSVGlobalMetadataDefaults();
 
-            for (final AbstractCalculationExportableResult<VegetationZonesCalculationResults> result : results.getResults()) {
-                final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
-                getHelper().addJRMetaDataUSINFO(source, results);
-
-                result.addReport(exportContextCSV, results, reporter, source);
-            }
-
-            reporter.exportPDF(out);
-        }
-        catch (final JRException je) {
-            getLog().warn("Error generating PDF Report!", je);
-        }
     }
 
     @Override
-    protected void doWriteCSVData(final CSVWriter writer, final VegetationZonesCalculationResults results) {
-        // TODO: Diesen Ablauf in super?
-
-        // TODO: move results into context?
-        final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, writer);
-
-        getLog().info("writeCSVData");
-
-        /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(results); // ggf auslagern innerhalb dieser Klasse
-
-        // writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
-
-        final RiverInfo river = results.getRiver();
-
-        final Class<?> lastResultType = null;
-
-        for (final AbstractCalculationExportableResult<VegetationZonesCalculationResults> result : results.getResults()) {
-
-            final Class<?> resultType = result.getClass();
-            if (lastResultType == null || lastResultType != resultType) {
-                exportContextCSV.writeBlankLine();
-                result.writeCSVHeader(exportContextCSV, results, river);
-                exportContextCSV.writeBlankLine();
-            } else
-                exportContextCSV.writeCSVLine(new String[] { "#" });
-
-            result.writeCsv(exportContextCSV, results);
-        }
+    protected void writePDFGlobalMetadata(final ExportContextPDF exportContext, final MetaAndTableJRDataSource source) {
+        exportContext.addJRMetaDataUSINFO(source);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesState.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesState.java	Fri Jun 29 14:54:40 2018 +0200
@@ -15,7 +15,6 @@
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DataFacet;
@@ -77,7 +76,7 @@
 
         final VegetationZonesCalculationResults results = (VegetationZonesCalculationResults) res.getData();
 
-        final List<AbstractCalculationExportableResult<VegetationZonesCalculationResults>> resultList = results.getResults();
+        final List<VegetationZonesCalculationResult> resultList = results.getResults();
 
         if (!resultList.isEmpty()) {
             final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
--- a/artifacts/src/main/resources/messages.properties	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Fri Jun 29 14:54:40 2018 +0200
@@ -1097,8 +1097,8 @@
 uinfo.export.csv.meta.header.veg.dauerbis = \u00dcberflutungsdauer bis [d/a]
 uinfo.export.url.inundationduration.inundationduration = \u00dcberflutungsdauer ({0})
 uinfo.export.url.inundationduration.vegetation = Vegetationszonen ({0})
-uinfo.export.url.inundationduration.vegetation_scenario= Vegetationszonen Szenario (Zeitraum: {0}, Szenario: {1})
-uinfo.export.url.inundationduration.scenario = \u00dcberflutungsdauer Szenario (Zeitraum: {0}, Szenario: {1})
+uinfo.export.url.inundationduration.vegetation_scenario= Vegetationszonen Szenario ({0}, {1}cm)
+uinfo.export.url.inundationduration.scenario = \u00dcberflutungsdauer Szenario ({0}, {1}cm)
 
 predefineddepthevol.total.title = Gesamt: {0}
 predefineddepthevol.peryear.title = J\u00e4hrlich: {0}
--- a/artifacts/src/main/resources/messages_de.properties	Fri Jun 29 13:09:29 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Fri Jun 29 14:54:40 2018 +0200
@@ -1097,8 +1097,8 @@
 uinfo.export.csv.meta.header.veg.dauerbis = \u00dcberflutungsdauer bis [d/a]
 uinfo.export.url.inundationduration.inundationduration = \u00dcberflutungsdauer ({0})
 uinfo.export.url.inundationduration.vegetation = Vegetationszonen ({0})
-uinfo.export.url.inundationduration.vegetation_scenario= Vegetationszonen Szenario (Zeitraum: {0}, Szenario: {1})
-uinfo.export.url.inundationduration.scenario = \u00dcberflutungsdauer Szenario (Zeitraum: {0}, Szenario: {1})
+uinfo.export.url.inundationduration.vegetation_scenario= Vegetationszonen Szenario ({0}, {1}cm)
+uinfo.export.url.inundationduration.scenario = \u00dcberflutungsdauer Szenario ({0}, {1}cm)
 
 predefineddepthevol.total.title = Gesamt: {0}
 predefineddepthevol.peryear.title = J\u00e4hrlich: {0}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ExportPanel.java	Fri Jun 29 13:09:29 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ExportPanel.java	Fri Jun 29 14:54:40 2018 +0200
@@ -95,20 +95,20 @@
         final String[] labelAndurlSplit = labelAndUrl.split(LABEL_URL_SEPARATOR);
         if (labelAndurlSplit.length == 2) {
 
-            final TextAreaItem label = new TextAreaItem();
-            label.setTitle(labelAndurlSplit[0]);
+            final TextAreaItem item = new TextAreaItem();
+            item.setTitle(labelAndurlSplit[0]);
 
-            label.setWrapTitle(true);
-            label.setTitleColSpan(3);
-            label.setColSpan(7);
-            label.setWidth(250);
+            item.setWrapTitle(true);
+            item.setTitleColSpan(3);
+            item.setColSpan(7);
+            item.setWidth(250);
+            item.setHeight(48);
+            item.setTitleAlign(Alignment.LEFT);
 
-            label.setTitleAlign(Alignment.LEFT);
+            item.setValue(labelAndurlSplit[1]);
+            item.setCanEdit(false);
 
-            label.setValue(labelAndurlSplit[1]);
-            label.setCanEdit(false);
-
-            return label;
+            return item;
         }
         return null;
     }

http://dive4elements.wald.intevation.org