changeset 9254:68ff4087b987

Zusammenführen
author gernotbelger
date Fri, 13 Jul 2018 11:40:25 +0200
parents eedb0bcf226b (current diff) c2a0028bfa9f (diff)
children 9be51f776798
files artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResult.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/LoadSingleEpochSelect.java
diffstat 56 files changed, 2869 insertions(+), 587 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/bundu.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/artifacts/bundu.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -325,7 +325,7 @@
     </transition>
 
 
-    <state id="state.bundu.yearselect" helpText="state.bundu.yearselect" description="state.bundu.yearselect" state="org.dive4elements.river.artifacts.states.LoadSingleYearSelectState">
+    <state id="state.bundu.yearselect" helpText="state.bundu.yearselect" description="state.bundu.yearselect" state="org.dive4elements.river.artifacts.bundu.bezugswst.LoadSingleYearSelectState">
       <data name="singleyear" type="String" />
     </state>
 
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -307,18 +307,12 @@
     <!-- Schrittweite benötigt für wq-state: TODO: vermutlich hier auch nicht? -->
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
       <from state="state.sinfo.calculation_mode" />
-      <to state="state.sinfo.distance" />
+      <to state="state.sinfo.distance_only" />
       <condition data="calculation_mode" value="sinfo_calc_flood_duration" operator="equal" />
-    </transition>
-
-    <state id="state.sinfo.distance" description="state.sinfo.distance" state="org.dive4elements.river.artifacts.states.DistanceSelect" helpText="help.state.sinfo.distance">
-      <data name="ld_from" type="Double" />
-      <data name="ld_to" type="Double" />
-      <data name="ld_step" type="Double" />
-    </state>
+    </transition> 
 
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
-      <from state="state.sinfo.distance" />
+      <from state="state.sinfo.distance_only" />
       <to state="state.sinfo.riverside" />
       <condition data="calculation_mode" value="sinfo_calc_flood_duration" operator="equal" />
     </transition>
@@ -372,7 +366,7 @@
        
           </facets>
         </outputmode>
-        <outputmode name="sinfo_flood_duration_curve" description="output.sinfo_duration_curve" mime-type="image/png" type="chart">
+        <outputmode name="sinfo_floodduration_curve" description="output.sinfo_duration_curve" mime-type="image/png" type="chart">
           <facets>
             <facet name="duration_curve.w" description="facet.duration_curve.w"/>
             <facet name="duration_curve.q" description="facet.duration_curve.q"/>
--- a/artifacts/doc/conf/artifacts/uinfo.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/artifacts/uinfo.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -78,6 +78,18 @@
 
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
       <from state="state.uinfo.scenario_type" />
+      <to state="state.uinfo.salix.supraregional" />
+      <condition data="scenario_selection" value="scenarioType.option2" operator="equal" />
+    </transition>
+
+    <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
+      <from state="state.uinfo.salix.supraregional" />
+      <to state="state.uinfo.salix_line" />
+      <condition data="calculation_mode" value="uinfo_salix_line" operator="equal" />
+    </transition>
+    
+    <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
+      <from state="state.uinfo.scenario_type" />
       <to state="state.uinfo.year_epoch" />
       <condition data="scenario_selection" value="scenarioType.option3" operator="equal" />
     </transition>
@@ -85,7 +97,9 @@
     <state id="state.uinfo.year_epoch" description="state.uinfo.year_epoch" state="org.dive4elements.river.artifacts.uinfo.salix.YearChoice" helpText="help.state.uinfo.year">
       <data name="ye_select" type="String" />
     </state>
-
+    <state id="state.uinfo.salix.supraregional" description="state.uinfo.salix.supraregional" state="org.dive4elements.river.artifacts.uinfo.salix.SupraRegionalTableState" helpText="help.state.uinfo.salix">
+      <data name="supraregional_table" type="String" />
+    </state>
 
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
       <from state="state.uinfo.year_epoch" />
@@ -104,7 +118,7 @@
     </state>
 
     <state id="state.uinfo.load.epoch" description="state.uinfo.load.epoch" state="org.dive4elements.river.artifacts.uinfo.salix.LoadSingleEpochSelectState" helpText="help.state.uinfo.load.epoch">
-      <data name="singleepoch" type="String" />
+      <data name="singleepoch" type="Integer" />
     </state>
 
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
@@ -118,9 +132,10 @@
       <condition data="calculation_mode" value="uinfo_salix_line" operator="equal" />
     </transition>
 
-    <state id="state.uinfo.distance_only_part.historical" description="state.uinfo.distance_only_part.historical" state="org.dive4elements.river.artifacts.states.DistanceOnlyPartSelect" helpText="help.state.uinfo.distance_only">
+    <state id="state.uinfo.distance_only_part.historical" description="state.uinfo.distance_only_part.historical" state="org.dive4elements.river.artifacts.uinfo.salix.DistanceOnlyPartHistoricalSelect" helpText="help.state.uinfo.distance_only">
       <data name="ld_from_part" type="Double" />
       <data name="ld_to_part" type="Double" />
+       <data name="bedheights_for_part" type="Double" />
     </state>
 
     <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition">
@@ -343,7 +358,7 @@
       <to state="state.uinfo.vegetation_zones.table" />
       <condition data="calculation_mode" value="uinfo_vegetation_zones" operator="equal" />
     </transition>
-
+ 
 
 
     <state id="state.uinfo.vegetation_zones.table" description="state.uinfo.vegetation_zones.table" state="org.dive4elements.river.artifacts.uinfo.vegetationzones.VegetationZonesTableEditState" helpText="help.state.uinfo.vegetation_zones">
--- a/artifacts/doc/conf/generators/generators.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/generators/generators.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -70,6 +70,8 @@
   <output-generator names="sinfo_tkh_report" class="org.dive4elements.river.exports.ReportGenerator" />
   <output-generator names="sinfo_floodduration_export" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationExporter" />
   <output-generator names="sinfo_floodduration_report" class="org.dive4elements.river.exports.ReportGenerator" />
+  <output-generator names="sinfo_floodduration_curve" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCurveGenerator" />
+  <output-generator names="sinfo_floodduration_curve_chartinfo" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCurveInfoGenerator" />
   <output-generator names="sinfo_collision_export" class="org.dive4elements.river.artifacts.sinfo.collision.CollisionExporter" />
   <output-generator names="sinfo_collision_report" class="org.dive4elements.river.exports.ReportGenerator" />
 
--- a/artifacts/doc/conf/jasper/templates/uinfo.salixline.jrxml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/jasper/templates/uinfo.salixline.jrxml	Fri Jul 13 11:40:25 2018 +0200
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Created with Jaspersoft Studio version 6.5.1.final using JasperReports Library version 4.5.0  -->
-<!-- 2018-06-06T13:16:36 -->
+<!-- 2018-07-10T15:31:50 -->
 <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="flysreport" language="groovy" pageWidth="595" pageHeight="842" columnWidth="545" leftMargin="30" rightMargin="20" topMargin="20" bottomMargin="20">
 	<property name="ireport.zoom" value="1.0"/>
 	<property name="ireport.x" value="0"/>
@@ -54,6 +54,7 @@
 	<field name="meta:salix_line" class="java.lang.String"/>
 	<field name="meta:salix_line_hist" class="java.lang.String"/>
 	<field name="meta:salix_line_scen" class="java.lang.String"/>
+	<field name="meta:salix_delta_mw" class="java.lang.String"/>
 	<field name="data:0" class="java.lang.String"/>
 	<field name="data:1" class="java.lang.String"/>
 	<field name="data:2" class="java.lang.String"/>
@@ -134,17 +135,11 @@
 				<reportElement key="" style="htmlStyle" positionType="Float" stretchType="RelativeToBandHeight" x="170" y="0" width="140" height="24"/>
 				<box padding="5"/>
 				<textElement textAlignment="Right" verticalAlignment="Bottom"/>
-				<textFieldExpression><![CDATA[$F{meta:salix_line_hist}]]></textFieldExpression>
+				<textFieldExpression><![CDATA[$F{meta:salix_delta_mw}]]></textFieldExpression>
 			</textField>
 			<line>
 				<reportElement style="htmlStyle" positionType="FixRelativeToBottom" x="0" y="24" width="550" height="1"/>
 			</line>
-			<textField isStretchWithOverflow="true">
-				<reportElement key="" style="htmlStyle" positionType="Float" stretchType="RelativeToBandHeight" x="310" y="0" width="140" height="24"/>
-				<box padding="5"/>
-				<textElement textAlignment="Right" verticalAlignment="Bottom"/>
-				<textFieldExpression><![CDATA[$F{meta:salix_line_scen}]]></textFieldExpression>
-			</textField>
 		</band>
 	</columnHeader>
 	<detail>
@@ -182,17 +177,6 @@
 				<textElement textAlignment="Right"/>
 				<textFieldExpression><![CDATA[$F{data:2}]]></textFieldExpression>
 			</textField>
-			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
-				<reportElement key="" style="htmlStyle" positionType="Float" stretchType="RelativeToBandHeight" x="310" y="0" width="140" height="15"/>
-				<box topPadding="2" leftPadding="5" bottomPadding="0" rightPadding="5">
-					<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
-					<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
-					<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
-					<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
-				</box>
-				<textElement textAlignment="Right"/>
-				<textFieldExpression><![CDATA[$F{data:3}]]></textFieldExpression>
-			</textField>
 		</band>
 	</detail>
 	<pageFooter>
--- a/artifacts/doc/conf/meta-data.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/meta-data.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -142,9 +142,6 @@
                   <dc:when test="$out = 'sinfo_flood_height'">
                     <dc:call-macro name="annotations" />
                   </dc:when>
-                  <dc:when test="$out = 'sinfo_flood_duration_curve'">
-                    <dc:call-macro name="annotations" />
-                  </dc:when>
                 </dc:choose>
               </dc:iterate>
             </dc:when>
--- a/artifacts/doc/conf/themes.xml	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/doc/conf/themes.xml	Fri Jul 13 11:40:25 2018 +0200
@@ -448,11 +448,9 @@
         <mapping from="sinfo_facet_flood_duration.left" to="SInfoFloodDurationLeft" />
         <mapping from="sinfo_facet_flood_duration.right" to="SInfoFloodDurationRight" />
         <mapping from="mainvalue.duration" to="SInfoMainValues" /> 
-        <mapping from="sinfo_facet_flood_height" to="SInfoInfrastructureHeight" />
         <mapping from="sinfo_facet_flood_height.left" to="SInfoInfrastructureHeightLeft" />
         <mapping from="sinfo_facet_flood_height.right" to="SInfoInfrastructureHeightRight" />
         <mapping from="mainvalue.w" to="SInfoMainValues" />
-      
         
         <mapping from="sinfo_facet_predefined_channel_width" to="SInfoPredefinedChannelWidth" />
         <mapping from="sinfo_facet_predefined_channel_depth" to="SInfoPredefinedChannelDepth" />
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractExportContext.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractExportContext.java	Fri Jul 13 11:40:25 2018 +0200
@@ -23,7 +23,7 @@
     private NumberFormat qFormat = null;
 
     private NumberFormat flowDepthFormat = null;
-
+    private NumberFormat salixScenFormat = null;
     private NumberFormat kmFormat = null;
 
     /** The CallContext object. */
@@ -70,6 +70,13 @@
         return this.flowDepthFormat;
     }
 
+    public final NumberFormat getSalixScenFormatter() {
+        if (this.salixScenFormat == null)
+            this.salixScenFormat = Formatter.getSalixLine(this.context);
+
+        return this.salixScenFormat;
+    }
+
     protected String msg(final String key) {
         return Resources.getMsg(this.context.getMeta(), key, key);
     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Fri Jul 13 11:40:25 2018 +0200
@@ -147,7 +147,8 @@
         SC("sinfo_collision"), //
         SFDUR("sinfo_flood_duration"), //
         STKH("sinfo_tkk"), //
-        SFW("sinfo_flood_height");
+        SFW("sinfo_flood_height"), //
+        SFDC("sinfo_floodduration_curve");
 
         private final String chartTypeString;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Fri Jul 13 11:40:25 2018 +0200
@@ -22,7 +22,6 @@
 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;
 
 /**
  * Calculation of the flood durations of the infrastructures of the km range of a river
@@ -49,21 +48,19 @@
 
         final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
         final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
-        final Infrastructure infrasSeries = Infrastructure.getSeries(river);
-        final String infrasType = (infrasSeries != null) ? infrasSeries.getType().getName() : "?";
-        final String label = infrasType + ", " + Resources.getMsg(this.context.getMeta(), access.getRiverside().getKey());
+        final String label = Resources.getMsg(this.context.getMeta(), access.getRiverside().getKey());
 
         final Calculation problems = new Calculation();
 
         // Calculate the selected main values, if any
         /* misuse winfo-artifact to calculate waterlevels in the same way */
         final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
-        // TODO Aktivieren wenn Step-Eingabe im Workflow weg: winfo.addStringData("ld_step", "100");
+        winfo.addStringData("ld_mode", "distance");
+        winfo.addStringData("ld_step", "100");
 
         final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange);
 
-        final FloodDurationCalculationResult result = calculateResult(label, calcRange, infoProvider, access.getRiverside(), problems, winfo);
-        results.addResult(result, problems);
+        calculateResult(label, calcRange, infoProvider, access.getRiverside(), problems, winfo, results);
 
         return new CalculationResult(results, problems);
     }
@@ -71,10 +68,10 @@
     /**
      * Calculates the flood durations of the infrastructures of a km range of a river
      */
-    private FloodDurationCalculationResult calculateResult(final String label, final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider,
-            final RiversideChoiceKey riverside, final Calculation problems, final WINFOArtifact winfo) {
+    private void calculateResult(final String label, final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider,
+            final RiversideChoiceKey riverside, final Calculation problems, final WINFOArtifact winfo, final FloodDurationCalculationResults results) {
 
         final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider);
-        return calculator.execute(problems, label, calcRange, riverside, winfo);
+        calculator.execute(problems, label, calcRange, riverside, winfo, results);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Fri Jul 13 11:40:25 2018 +0200
@@ -76,8 +76,7 @@
         if (this.mainvalueLabels.length >= 1) {
             // "##METADATEN WASSERSPIEGELLAGE"
             exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL);
-            for (int i = 1; i <= getWaterlevelCount(); // this.mainvalueLabels.length;
-                    i++) {
+            for (int i = 1; i <= getWaterlevelCount(); i++) {
                 // "# Bezeichnung der Wasserspiegellage: "
                 final String label = this.getMainValueLabel(i - 1);
                 exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_NAME, String.format("%d: %s", i, label));
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Fri Jul 13 11:40:25 2018 +0200
@@ -11,6 +11,7 @@
 
 import org.apache.commons.lang.math.DoubleRange;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
+import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
@@ -23,4 +24,14 @@
     public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
         super(calcModeLabel, user, river, calcRange);
     }
+
+    private CalculationResult durationCurve;
+
+    public CalculationResult getDurationCurve() {
+        return this.durationCurve;
+    }
+
+    public void setDurationCurve(final CalculationResult durationCurve) {
+        this.durationCurve = durationCurve;
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Fri Jul 13 11:40:25 2018 +0200
@@ -25,6 +25,7 @@
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.Calculation.Problem;
 import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.WQDay;
 import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.artifacts.sinfo.common.GaugeDurationValuesFinder;
 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
@@ -60,8 +61,8 @@
     /**
      * Calculate the infrastructures flood duration result rows
      */
-    public FloodDurationCalculationResult execute(final Calculation problems, final String label, final DoubleRange calcRange,
-            final RiversideChoiceKey riverside, final WINFOArtifact winfo) {
+    public void execute(final Calculation problems, final String label, final DoubleRange calcRange,
+            final RiversideChoiceKey riverside, final WINFOArtifact winfo, final FloodDurationCalculationResults results) {
 
         // Find all gauges of the calc range, and create the duration finders
         final Map<Gauge, GaugeDurationValuesFinder> durFinders = new HashMap<>();
@@ -113,8 +114,29 @@
                 this.rows.add(row2);
             }
         }
+        results.addResult(new FloodDurationCalculationResult(label, mainValueLabels, this.rows), problems);
+        calcWQDays(problems, stationsSorted[0], AttributeKey.LEFT, winfo, results);
+    }
 
-        return new FloodDurationCalculationResult(label, mainValueLabels, this.rows);
+    public void calcWQDays(final Calculation problems, final double station, final AttributeKey riverside, final WINFOArtifact winfo,
+            final FloodDurationCalculationResults results) {
+
+        winfo.addStringData("ld_locations", Double.toString(station));
+        final CalculationResult res = winfo.getDurationCurveData();
+        final WQDay underflow = (WQDay) res.getData();
+        // Transform underflow days into overflow days and re-sort
+        final int[] days = new int[underflow.getWs().length];
+        final double[] ws = new double[days.length];
+        final double[] qs = new double[days.length];
+        for (int i = 0, j = days.length - 1; i <= days.length - 1; i++, j--) {
+            days[j] = 365 - underflow.getDay(i);
+            ws[j] = underflow.getW(i);
+            qs[j] = underflow.getQ(i);
+        }
+        res.setData(new WQDay(days, ws, qs));
+        // TODO Infrastrukturhoehe
+        // TODO WSPL/Hauptwerte
+        results.setDurationCurve(res);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveFacet.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.DefaultFacet;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.WQDay;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Data of a duration curve.
+ */
+public class FloodDurationCurveFacet extends DefaultFacet {
+
+    private static Logger log = Logger.getLogger(FloodDurationCurveFacet.class);
+
+    /** Blackboard data provider key for durationcurve (wqday) data. */
+    public static String BB_DURATIONCURVE = "durationcurve";
+
+    /** Blackboard data provider key for km of durationcurve. */
+    public static String BB_DURATIONCURVE_KM = "durationcurve.km";
+
+    public FloodDurationCurveFacet() {
+    }
+
+    public FloodDurationCurveFacet(final String name, final String description) {
+        super(0, name, description);
+    }
+
+
+    /**
+     * Expose state computation from SINFOArtifact.
+     */
+    @Override
+    public Object getData(final Artifact artifact, final CallContext context) {
+
+        log.debug("Get data for flood duration curve data");
+
+        final D4EArtifact flys = (D4EArtifact) artifact;
+
+        final CalculationResult res = (CalculationResult) flys.compute(context, ComputeType.ADVANCE, false);
+
+        final FloodDurationCalculationResults data = (FloodDurationCalculationResults) res.getData();
+
+        return data.getDurationCurve();
+        // return getTestData();
+    }
+
+    private WQDay getTestData() {
+        final int[] days = new int[366];
+        final double[] ws = new double[366];
+        final double[] qs = new double[366];
+        for (int i = 0; i <= 365; i++) {
+            days[i] = i;
+            final double x = (i - 182.5) / 182.5;
+            ws[i] = 102.0 - (Math.pow(x, 5) + x);
+            qs[i] = 1600.0 - 800 * (Math.pow(x, 9) + x);
+        }
+        return new WQDay(days, ws, qs);
+    }
+
+
+    @Override
+    public List getStaticDataProviderKeys(final Artifact art) {
+        final List list = new ArrayList();
+        list.add(BB_DURATIONCURVE);
+        list.add(BB_DURATIONCURVE_KM);
+        return list;
+    }
+
+
+    /**
+     * Can provide whatever getData returns and additionally the location.
+     * @param key      will respond on BB_DURATIONCURVE +KM
+     * @param param    ignored
+     * @param context  ignored
+     * @return whatever getData delivers or location.
+     */
+    @Override
+    public Object provideBlackboardData(final Artifact artifact,
+            final Object key,
+            final Object param,
+            final CallContext context
+            ) {
+        if (key.equals(BB_DURATIONCURVE)) {
+            return getData(artifact, context);
+        }
+        else if (key.equals(BB_DURATIONCURVE_KM)) {
+            return ((D4EArtifact)artifact).getDataAsString("ld_locations");
+        }
+        else {
+            return null;
+        }
+    }
+
+
+    /** Create a deep copy. */
+    @Override
+    public Facet deepCopy() {
+        final FloodDurationCurveFacet copy = new FloodDurationCurveFacet();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,258 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.awt.Font;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.FacetTypes;
+import org.dive4elements.river.artifacts.model.WQDay;
+import org.dive4elements.river.exports.IdentifiableNumberAxis;
+import org.dive4elements.river.exports.XYChartGenerator;
+import org.dive4elements.river.jfree.Bounds;
+import org.dive4elements.river.jfree.RiverAnnotation;
+import org.dive4elements.river.jfree.StyledXYSeries;
+import org.dive4elements.river.themes.ThemeDocument;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.Range;
+import org.jfree.data.xy.XYSeries;
+
+
+/**
+ * An OutGenerator that generates duration curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FloodDurationCurveGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public static enum YAXIS {
+        W(0),
+        Q(1);
+        public int idx;
+        private YAXIS(final int c) {
+            this.idx = c;
+        }
+    }
+
+    /** Local log. */
+    private static Logger log =
+            Logger.getLogger(FloodDurationCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "sinfo.chart.flood_duration.curve.section.title";
+
+    public static final String I18N_CHART_SUBTITLE = "chart.duration.curve.subtitle";
+
+    public static final String I18N_XAXIS_LABEL = "sinfo.chart.flood_duration.curve.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL_W = "chart.duration.curve.yaxis.label.w";
+
+    public static final String I18N_YAXIS_LABEL_Q = "chart.duration.curve.yaxis.label.q";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Dauerlinie";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Überflutungsdauer [d/a]";
+
+
+    public FloodDurationCurveGenerator() {
+        super();
+    }
+
+
+    /**
+     * Create Axis for given index.
+     * @return axis with according internationalized label.
+     */
+    @Override
+    protected NumberAxis createYAxis(final int index) {
+        final Font labelFont = new Font("Tahoma", Font.BOLD, 14);
+        final String label   = getYAxisLabel(index);
+
+        final NumberAxis axis = createNumberAxis(index, label);
+        if (index == YAXIS.W.idx) {
+            axis.setAutoRangeIncludesZero(false);
+        }
+        axis.setLabelFont(labelFont);
+        return axis;
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle(final CallContext context) {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+
+    @Override
+    protected String getDefaultChartSubtitle(final CallContext context) {
+
+        final double[] dist  = getRange();
+        return msg(I18N_CHART_SUBTITLE, "", getRiverName(), dist[0]);
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel(final CallContext context) {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(final int index) {
+
+        String label = "default";
+        if (index == YAXIS.W.idx) {
+            label = msg(I18N_YAXIS_LABEL_W, I18N_YAXIS_LABEL_W, getRiverUnit());
+        }
+        else if (index == YAXIS.Q.idx) {
+            label = msg(I18N_YAXIS_LABEL_Q);
+        }
+        return label;
+    }
+
+
+    @Override
+    protected boolean zoomX(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) {
+
+        final boolean zoomin = super.zoom(plot, axis, bounds, x);
+        if (!zoomin)
+            axis.setLowerBound(0d);
+        // axis.setUpperBound(364);
+        return zoomin;
+    }
+
+
+    /**
+     * This method overrides the method in the parent class to set the lower
+     * bounds of the Q axis to 0. This axis should never display negative
+     * values on its own.
+     */
+    @Override
+    protected boolean zoomY(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) {
+
+        final boolean zoomin = super.zoom(plot, axis, bounds, x);
+        if (!zoomin && axis instanceof IdentifiableNumberAxis) {
+            final String id = ((IdentifiableNumberAxis) axis).getId();
+            if (YAXIS.Q.toString().equals(id))
+                axis.setLowerBound(0d);
+        }
+        return zoomin;
+    }
+
+
+    @Override
+    public void doOut(final ArtifactAndFacet artifactFacet, final ThemeDocument attr, final boolean visible) {
+
+        final String name = artifactFacet.getFacetName();
+
+        log.debug("FloodDurationCurveGenerator.doOut: " + name);
+
+        if (name == null || name.length() == 0) {
+            log.error("No facet given. Cannot create dataset.");
+            return;
+        }
+
+        final CallContext context = getContext();
+
+        if (name.equals(DURATION_W)) {
+            doWOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible);
+        }
+        else if (name.equals(DURATION_Q)) {
+            doQOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible);
+        }
+        else if (name.equals(MAINVALUES_Q) || name.equals(MAINVALUES_W)) {
+            doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible);
+        }
+        else if (name.equals(RELATIVE_POINT)) {
+            doPointOut((Point2D) artifactFacet.getData(context), artifactFacet, attr, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context), artifactFacet, attr, visible, YAXIS.W.idx);
+        }
+        else {
+            log.warn("Unknown facet name: " + name);
+            return;
+        }
+    }
+
+    /**
+     * Creates the series for a duration curve's W facet.
+     *
+     * @param wqdays The WQDay store that contains the Ws.
+     * @param theme
+     */
+    protected void doWOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doWOut");
+        final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        final int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            final int  day = wqdays.getDay(i);
+            final double w = wqdays.getW(i);
+            series.add(day, w);
+        }
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    protected void doPointOut(final Point2D point, final ArtifactAndFacet aandf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doPointOut");
+        final XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        series.add(point.getX(), point.getY());
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+
+    /**
+     * Creates the series for a duration curve's Q facet.
+     *
+     * @param wqdays The WQDay store that contains the Qs.
+     * @param theme
+     */
+    protected void doQOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doQOut");
+        final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        final int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            final int  day = wqdays.getDay(i);
+            final double q = wqdays.getQ(i);
+            series.add(day, q);
+        }
+        addAxisSeries(series, YAXIS.Q.idx, visible);
+    }
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(final int idx) {
+                final YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    // MainValue-Annotations should be visualized by
+    // a line that goes to the curve itself.
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveInfoGenerator.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,26 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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 org.dive4elements.river.exports.ChartInfoGenerator;
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific duration
+ * curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FloodDurationCurveInfoGenerator
+extends      ChartInfoGenerator
+{
+    public FloodDurationCurveInfoGenerator() {
+        super(new FloodDurationCurveGenerator());
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,74 @@
+/** 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.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.exports.DurationCurveGenerator;
+import org.dive4elements.river.exports.XYChartGenerator;
+import org.dive4elements.river.exports.process.DefaultProcessor;
+import org.dive4elements.river.themes.ThemeDocument;
+
+/**
+ * Processor to generate the facet and data series of a flood duration curve
+ *
+ * @author Matthias Schäfer
+ *
+ */
+public final class FloodDurationCurveProcessor extends DefaultProcessor {
+
+    private static final String FACET_FLOOD_DURATION_W = "duration_curve.w";
+
+    private static final String FACET_FLOOD_DURATION_Q = "duration_curve.q";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_W);
+        HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_Q);
+    }
+
+    public static Facet createFloodDurationWCurveFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int facetIndex, final int resultIndex, final String description) {
+
+        return new FloodDurationCurveFacet(FACET_FLOOD_DURATION_W, description);
+    }
+
+    public static Facet createFloodDurationQCurveFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int facetIndex, final int resultIndex, final String description) {
+
+        return new FloodDurationCurveFacet(FACET_FLOOD_DURATION_Q, description);
+    }
+
+    /**
+     * Processes data to generate a chart.
+     */
+    @Override
+    public void doOut(final XYChartGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible, final int index) {
+
+    }
+
+    @Override
+    public final String getAxisLabel(final DiagramGenerator generator) {
+        return generator.msg(DurationCurveGenerator.I18N_YAXIS_LABEL_W);
+    }
+
+    @Override
+    public final boolean canHandle(final String facettype) {
+        return HANDLED_FACET_TYPES.contains(facettype);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Fri Jul 13 11:40:25 2018 +0200
@@ -20,6 +20,7 @@
 import org.dive4elements.river.artifacts.model.EmptyFacet;
 import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.artifacts.model.ReportFacet;
+import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.RiversideRadioChoice.RiversideChoiceKey;
 import org.dive4elements.river.artifacts.states.DefaultState;
@@ -94,7 +95,7 @@
 
             for (int j = 0; j < waterlevelCount; j++) {
 
-                final String waterlevelLabel = result.getMainValueLabel(j);
+                // final String waterlevelLabel = result.getMainValueLabel(j);
                 // FIXME: use label as label for theme
 
                 // final int facetIndex, final int resultIndex, final int dataIndex
@@ -104,6 +105,11 @@
                 themeCount++;
             }
 
+            final String nameW = Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.w");
+            final String nameQ = Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.q");
+            facets.add(FloodDurationCurveProcessor.createFloodDurationWCurveFacet(context, hash, this.id, result, 0, resultIndex, nameW));
+            facets.add(FloodDurationCurveProcessor.createFloodDurationQCurveFacet(context, hash, this.id, result, 1, resultIndex, nameQ));
+
             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));
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/commons/UInfoResultType.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/commons/UInfoResultType.java	Fri Jul 13 11:40:25 2018 +0200
@@ -40,6 +40,69 @@
         return null;
     }
 
+    public static final UInfoResultType customMultiRowColSalixRegionalValue_Dwspl = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.scenario") {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+            throw new UnsupportedOperationException();
+        }
+    };
+
+    public static final UInfoResultType salix_line_scenario = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.scenario") {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            final double doubleValue = asDouble(value);
+            return exportDoubleValue(context, doubleValue);
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+            // REMARK: other modules use Formatter.getWaterlevelW(context) instead, but that format with a variable number of
+            // digits.
+            return Formatter.getSalixLine(context);
+        }
+    };
+
+    public static final UInfoResultType salix_line_scenario_dwspl = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.scenario_dwspl") {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            final String valueStr = String.valueOf(value);
+            return exportStringValue(valueStr);
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+
+            return Formatter.getIntegerFormatter(context);
+        }
+    };
+    public static final UInfoResultType salix_delta_mw = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.delta_mw") {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            final double doubleValue = asDouble(value);
+            return exportDoubleValue(context, doubleValue);
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+            // REMARK: other modules use Formatter.getWaterlevelW(context) instead, but that format with a variable number of
+            // digits.
+            return Formatter.getSalixLine(context);
+        }
+    };
+
     public static final UInfoResultType salixline = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.salix_line") {
         private static final long serialVersionUID = 1L;
 
@@ -74,23 +137,6 @@
         }
     };
 
-    public static final UInfoResultType salixlinescen = new UInfoResultType(null, "uinfo.export.salix_line.csv.header.scen") {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public String exportValue(final CallContext context, final Object value) {
-            final double doubleValue = asDouble(value);
-            return exportDoubleValue(context, doubleValue);
-        }
-
-        @Override
-        protected NumberFormat createFormatter(final CallContext context) {
-            // REMARK: other modules use Formatter.getWaterlevelW(context) instead, but that format with a variable number of
-            // digits.
-            return Formatter.getSalixLine(context);
-        }
-    };
-
     public static final UInfoResultType vegname = new UInfoResultType(null, "uinfo.export.csv.meta.header.veg.name") {
         private static final long serialVersionUID = 1L;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/DistanceOnlyPartHistoricalSelect.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,188 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.uinfo.salix;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.AddTableDataHelper;
+import org.dive4elements.river.artifacts.states.DistanceOnlySelect;
+import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
+import org.dive4elements.river.model.BedHeight;
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.Formatter;
+import org.w3c.dom.Element;
+
+public class DistanceOnlyPartHistoricalSelect extends DistanceOnlySelect {
+
+    private static final long serialVersionUID = 1L;
+    private static Logger log = Logger.getLogger(DistanceOnlyPartHistoricalSelect.class);
+
+    List<BedHeight> bhs = null;
+    Integer epoch = null;
+    Integer year = null;
+    Double lowerKm = null;
+    Double upperKm = null;
+    River river = null;
+
+    @Override
+    protected String getUIProvider() {
+        return "distance_only_part_historical_panel";
+    }
+
+    @Override
+    protected String getTitle(final CallContext context) {
+        // REMARK: that is how it should be: return Resources.getMsg(context.getMeta(), getID());
+        return Resources.getMsg(context.getMeta(), "state.title.distance_part_state");
+    }
+
+    @Override
+    protected void appendItems(final Artifact artifact, final ElementCreator creator, final String name, final CallContext context, final Element select) {
+        final String datakey = "bedheights_for_part";
+
+        try {
+            if (datakey.equals(name)) {
+                makeDataSourceYearEpoch(artifact, creator, select, context, getBedheights(artifact)); // ist nur n test
+            } else if (name.equals("ld_from_part")) {
+
+                final SalixLineAccess access = new SalixLineAccess((UINFOArtifact) artifact);
+                final double lowerSoundings = this.getLowerUpperKmRange(getBedheights(artifact))[0];
+                final double lowerKm = access.getLowerKm() > lowerSoundings ? access.getLowerKm() : lowerSoundings;
+
+                creator.addAttr(select, "type", "options", true);
+
+                final Element item = creator.create("item");
+                creator.addAttr(item, "label", "from_test", true);
+                creator.addAttr(item, "value", String.valueOf(lowerKm), true);
+
+                select.appendChild(item);
+            }
+
+            else if (name.equals("ld_to_part")) {
+                final SalixLineAccess access = new SalixLineAccess((UINFOArtifact) artifact);
+                final double upperSoundings = this.getLowerUpperKmRange(getBedheights(artifact))[1];
+                final double upperKm = access.getUpperKm() < upperSoundings ? access.getUpperKm() : upperSoundings;
+
+                creator.addAttr(select, "type", "options", true);
+
+                final Element item = creator.create("item");
+                creator.addAttr(item, "label", "to_test", true);
+                creator.addAttr(item, "value", String.valueOf(upperKm), true);
+
+                select.appendChild(item);
+
+            }
+        }
+        catch (
+
+        final IllegalArgumentException iae) {
+            iae.printStackTrace();
+        }
+    }
+
+    private List<BedHeight> getBedheights(final Artifact artifact) {
+
+        final SalixLineAccess access = new SalixLineAccess((UINFOArtifact) artifact); // improved lazy-loading
+        final Integer year = access.getYear();
+        final Integer epoch = access.getEpoch();
+        final River river = access.getRiver(); // comparable? workflow does not allow return and change anyway...
+        final Double lower = access.getLowerKm();
+        final Double upper = access.getUpperKm();
+        if (!(this.year == year && this.epoch == epoch && this.river == river && this.lowerKm == lower && this.upperKm == upper)) {
+            this.bhs = null;
+        }
+        if (this.bhs == null) {
+            final boolean isEpoch = epoch == null ? false : true;
+            this.bhs = BedHeight.getBedHeightYearEpoch(isEpoch, isEpoch ? epoch : year, river, lower, upper);
+            this.year = year;
+            this.epoch = epoch;
+            this.river = river;
+            this.lowerKm = lower;
+            this.upperKm = upper;
+        }
+        return this.bhs;
+
+    }
+
+    private static final void makeDataSourceYearEpoch(final Artifact artifact, final ElementCreator creator, final Element select, final CallContext context,
+            final List<BedHeight> bedheights) {
+
+        final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "year", context.getMeta());
+
+        // TODO: probably aggregating results, no sound-row, output as single row
+
+        int year = 0; // hässlich, aber kommt vermutlich eh bald weg
+        if (bedheights != null && bedheights.size() > 0)
+            year = bedheights.get(0).getYear(); // das jahr/epoche ist immer dasselbe
+
+        helper.addColumn(0, "year", "60", "year", "INTEGER", "LEFT", null);
+        helper.addColumn(1, "range", "130", "state.uinfo.salix.historical.km_range_part", "STRING", "LEFT", null);
+        helper.addColumn(2, "description", "500", "uinfo.salix.sounding", "STRING", "LEFT", null);
+
+        final TreeMap<String, String> bedHeightSorted = new TreeMap<>();
+        final double min = Double.MAX_VALUE;
+        final double max = -Double.MAX_VALUE;
+        final java.text.NumberFormat formatter = Formatter.getCalculationKm(context.getMeta());
+
+        for (final BedHeight bh : bedheights) {
+            final org.dive4elements.river.model.Range range = BedHeight.getRangeFromBedHeights(bh);
+            final Double from = range.getA().doubleValue(); // NullPointer check??
+            final Double to = range.getB().doubleValue();
+
+            bedHeightSorted.put(bh.getDescription(), formatter.format(from) + " - " + formatter.format(to));
+        }
+        final Iterator<String> iterator = bedHeightSorted.keySet().iterator();
+        while (iterator.hasNext()) {
+            final String descr = iterator.next();
+            final String fromTo = bedHeightSorted.get(descr);
+            final Map<String, String> row = new HashMap<>();
+            row.put("year", String.valueOf(year));
+            row.put("range", fromTo);
+            row.put("description", descr);
+            helper.addRow(row);
+        }
+
+        helper.submitMapToXml();
+    }
+
+    private double[] getLowerUpperKmRange(final List<BedHeight> bedheights) {
+        double min = Double.MAX_VALUE;
+        double max = -Double.MAX_VALUE;
+
+        for (final BedHeight bh : bedheights) {
+            final org.dive4elements.river.model.Range range = BedHeight.getRangeFromBedHeights(bh);
+            try {
+                final Double from = range.getA().doubleValue(); // NullPointer check?? -> try catch
+                final Double to = range.getB().doubleValue();
+
+                final double upper = to > from ? to : from;
+                final double lower = from < to ? from : to;
+                if (upper > max)
+                    max = upper;
+
+                if (lower < min)
+                    min = lower;
+            }
+            catch (final Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+        return new double[] { min, max };
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadScenarioSelectLimit5.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadScenarioSelectLimit5.java	Fri Jul 13 11:40:25 2018 +0200
@@ -45,16 +45,10 @@
             if (datakey.equals(name)) {
 
                 final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "cm", context.getMeta());
-                // no input help wanted
-                // helper.addColumn(0, "pinfrom", "40", "common.client.ui.from", "ICON", "CENTER", "from");
-                // helper.addColumn(1, "pinto", "40", "common.client.ui.to", "ICON", "CENTER", "to");
-                // helper.addColumn(1, "cm", "60", "Delta [cm]", "INTEGER", "RIGHT", null);
-
                 for (int i = -200; i < 210; i = i + 10) {
                     final Map<String, String> row = new HashMap<>();
                     row.put("cm", Integer.toString(i));
                     helper.addRow(row);
-
                 }
                 helper.submitMapToXml();
             }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadSingleEpochSelectState.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadSingleEpochSelectState.java	Fri Jul 13 11:40:25 2018 +0200
@@ -9,7 +9,10 @@
 package org.dive4elements.river.artifacts.uinfo.salix;
 
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.Artifact;
@@ -17,6 +20,8 @@
 import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
 import org.dive4elements.river.artifacts.states.AddTableDataHelper;
 import org.dive4elements.river.artifacts.states.DefaultState;
+import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
+import org.dive4elements.river.model.BedHeight;
 import org.w3c.dom.Element;
 
 public class LoadSingleEpochSelectState extends DefaultState {
@@ -32,38 +37,18 @@
 
     @Override
     protected String getUIProvider() {
-        return "common.load_single_epoch_select";
+        return "uinfo.salix.load_single_year_pseudo_epoch_select";
     }
 
     @Override
     protected void appendItems(final Artifact artifact, final ElementCreator creator, final String name, final CallContext context, final Element select) {
         final String datakey = "singleepoch";
-        // TODO: MAKE DATASOURCE
+
         try {
             if (datakey.equals(name)) {
-
-                final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "year", context.getMeta());
-
-                helper.addColumn(0, "pinfrom", "40", "common.client.ui.from", "ICON", "CENTER", "from");
-                helper.addColumn(1, "pinto", "40", "common.client.ui.to", "ICON", "CENTER", "to");
-                helper.addColumn(2, "year", "60", "year", "INTEGER", "LEFT", null);
-                helper.addColumn(3, "sounding", "200", "uinfo.salix.soundings", "STRING", "LEFT", null);
-                // final CollisionAccess access = new CollisionAccess((SINFOArtifact) artifact); // Der River wurde im vorigen State
-                // bereits gesetzt
-
-                // final List<Collision> collisions = CollisionHibernateFactory.getCollisionsByRiver(access.getRiver());
-                // for (final Collision coll : collisions) { // TODO: Filter on Range (?)
-                // final Integer year = coll.getYear();
-                // for (final Collision coll : collisions) {
-                for (int i = 0; i < 3; i++) {// : Collision.getYearsOfRiver(access.getRiver())) {
-                    // final Integer year = coll.getYear();
-                    final Map<String, String> row = new HashMap<>();
-                    row.put("year", String.valueOf(1995 + i)); // Nullpointer?
-                    row.put("sounding", "TODO: Peilungen für das Jahr in dieser Zelle auflisten.");
-                    helper.addRow(row);
-                }
-                // }
-                helper.submitMapToXml();
+                final SalixLineAccess access = new SalixLineAccess((UINFOArtifact) artifact);
+                final List<BedHeight> bhs = BedHeight.getBedHeightEpochs(access.getRiver(), access.getLowerKm(), access.getUpperKm());
+                makeDataSourceYearEpoch(artifact, creator, select, context, bhs);
             }
         }
         catch (
@@ -72,4 +57,34 @@
             iae.printStackTrace();
         }
     }
+
+    public static final void makeDataSourceYearEpoch(final Artifact artifact, final ElementCreator creator, final Element select, final CallContext context,
+            final List<BedHeight> bedheights) { // TODO: maybe move to appropriate helper...
+
+        final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "year", context.getMeta());
+
+        helper.addColumn(0, "pinfrom", "40", "common.client.ui.from", "ICON", "CENTER", "from");
+        helper.addColumn(1, "year", "60", "year", "INTEGER", "LEFT", null);
+        helper.addColumn(2, "sounding", "500", "uinfo.salix.soundings", "STRING", "LEFT", null);
+
+        final TreeMap<Integer, String> bedHeightSorted = new TreeMap<>();
+
+        for (final BedHeight bh : bedheights) {
+            final int year = bh.getYear();
+            final String soundings = bedHeightSorted.containsKey(year) ? bedHeightSorted.get(year) + ", " : "";
+            bedHeightSorted.put(year, soundings + bh.getDescription());
+        }
+        final Iterator<Integer> iterator = bedHeightSorted.keySet().iterator();
+        while (iterator.hasNext()) {
+            final int year = iterator.next();
+            final String soundings = bedHeightSorted.get(year);
+            final Map<String, String> row = new HashMap<>();
+            row.put("year", String.valueOf(year));
+            row.put("sounding", soundings);
+            helper.addRow(row);
+        }
+
+        helper.submitMapToXml();
+    }
+
 }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadSingleYearSelectState.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/LoadSingleYearSelectState.java	Fri Jul 13 11:40:25 2018 +0200
@@ -8,15 +8,15 @@
 
 package org.dive4elements.river.artifacts.uinfo.salix;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
 
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
-import org.dive4elements.river.artifacts.states.AddTableDataHelper;
 import org.dive4elements.river.artifacts.states.DefaultState;
+import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
+import org.dive4elements.river.model.BedHeight;
 import org.w3c.dom.Element;
 
 /** State in which to fetch years for sedminent load calculation. */
@@ -39,35 +39,21 @@
 
     @Override
     protected void appendItems(final Artifact artifact, final ElementCreator creator, final String name, final CallContext context, final Element select) {
-        // TODO: MAKE DATASOURCE
-        try {
-            final String dataKeyofState = "singleyear";// siehe .xml
-            if (dataKeyofState.equals(name)) {
-
-                final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "year", context.getMeta()); // "year" not to be confused with datakey
 
-                helper.addColumn(0, "pinfrom", "60", "common.client.ui.selection", "ICON", "CENTER", "from");
-                helper.addColumn(1, "year", "60", "year", "INTEGER", "LEFT", null);
-                helper.addColumn(2, "sounding", "200", "uinfo.salix.soundings", "STRING", "LEFT", null);
-                // TODO: MAKE DATASOURCE
-                // final CollisionAccess access = new CollisionAccess((SINFOArtifact) artifact); // TODO: MAKE DATASOURCE
-                // TODO: MAKE DATASOURCE
-                // final List<Collision> collisions = CollisionHibernateFactory.getCollisionsByRiver(access.getRiver());
-                // for (final Collision coll : collisions) {
-                for (int i = 0; i < 3; i++) {// : Collision.getYearsOfRiver(access.getRiver())) {
-                    // final Integer year = coll.getYear();
-                    final Map<String, String> row = new HashMap<>();
-                    row.put("year", String.valueOf(1995 + i)); // Nullpointer?
-                    row.put("sounding", "TODO: Peilungen für das Jahr in dieser Zelle auflisten.");
-                    helper.addRow(row);
-                }
-                helper.submitMapToXml();
+        final String dataKeyofState = "singleyear";// siehe .xml
+        try {
+            if (dataKeyofState.equals(name)) {
+                final SalixLineAccess access = new SalixLineAccess((UINFOArtifact) artifact);
+                final List<BedHeight> bhs = BedHeight.getBedHeightYear(access.getRiver(), access.getLowerKm(), access.getUpperKm());
+                LoadSingleEpochSelectState.makeDataSourceYearEpoch(artifact, creator, select, context, bhs);
             }
         }
-        catch (final IllegalArgumentException iae) {
+        catch (
+
+        final IllegalArgumentException iae) {
             iae.printStackTrace();
         }
+
     }
-
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineAccess.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineAccess.java	Fri Jul 13 11:40:25 2018 +0200
@@ -58,4 +58,36 @@
     public Double getToPart() {
         return getDouble("ld_to_part");
     }
+
+    public int[] getRegionalScenarioIntegers() {
+        // super.getIntArray("sedimentheight"); DOES NOT WORK!
+        final String ints = super.getString("sedimentheight");
+        if (ints != null) {
+            final String[] intsSplit = ints.split(" ");
+            final int[] values = new int[intsSplit.length];
+            for (int i = 0; i < intsSplit.length; i++) {
+                values[i] = Integer.valueOf(intsSplit[i]);
+            }
+            return values;
+        }
+        return null;
+    }
+
+    public String getSupraRegionalString() {
+        return super.getString("supraregional_table");
+    }
+
+    public Integer getYear() {
+        if (getString("ye_select").equals("state.uinfo.year")) {
+            return super.getInteger("singleyear");
+        }
+        return null;
+    }
+
+    public Integer getEpoch() {
+        if (getString("ye_select").equals("state.uinfo.epoch")) {
+            return super.getInteger("singleepoch");
+        }
+        return null;
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculation.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculation.java	Fri Jul 13 11:40:25 2018 +0200
@@ -11,6 +11,10 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.lang.math.DoubleRange;
 import org.dive4elements.artifacts.CallContext;
@@ -53,6 +57,9 @@
         final String selectedScenario = accessSalix.getScenario();
         final Double fromPart = accessSalix.getFromPart();
         final Double toPart = accessSalix.getToPart();
+
+        final boolean useSCenario = accessSalix.getUseScenario();
+        final String scenario = accessSalix.getScenario();
         // calculation_mode
         // ld_from , ld_to
         // use_scenario (boolean)
@@ -64,26 +71,88 @@
         final SalixLineCalculationResults results = new SalixLineCalculationResults(calcModeLabel, user, riverInfo, range);
 
         final Collection<ResultRow> rows = new ArrayList<>();
-
+        SalixLineCalculationNoScenarioResult result = null; // verzweigung etwas ungünstig. möglicherweise auch die Abstraktion. ist erstmal nur ne idee
         final ResultRow row1 = ResultRow.create(). //
                 putValue(GeneralResultType.station, 100).//
                 putValue(UInfoResultType.salixline, 28).//
-                putValue(UInfoResultType.salixlinehist, 2).//
-                putValue(UInfoResultType.salixlinescen, 82);
-        rows.add(row1);
+                putValue(UInfoResultType.salix_delta_mw, 2);
 
-        final ResultRow row2 = ResultRow.create(). //
-                putValue(GeneralResultType.station, 200). //
-                putValue(UInfoResultType.salixline, 3). //
-                putValue(UInfoResultType.salixlinehist, 2).//
-                putValue(UInfoResultType.salixlinescen, 822);
+        if (!useScenario) {
 
-        rows.add(row2);
+            rows.add(row1);
+            result = new SalixLineCalculationNoScenarioResult("Ergebnis 1", null, rows);
+        } else {
 
-        final SalixLineCalculationResult result = new SalixLineCalculationResult("Ergebnis 1", null, rows);
+            if (scenario.equals("scenarioType.option1")) { // REGIONAL
 
+                final int[] scenarios = accessSalix.getRegionalScenarioIntegers();
+                final List<SalixScenario> list = new ArrayList<>();
+                for (final int scen_val : scenarios) {
+                    list.add(new SalixScenario(scen_val, 666.));// TODO: replace 666 by real calculated value
+                }
+                row1.putValue(UInfoResultType.customMultiRowColSalixRegionalValue_Dwspl, list);//
+                rows.add(row1);
+                result = new SalixLineCalculationRegionalResult("Ergebnis 1 regional test", null, rows, scenarios);
+
+            } else if (scenario.equals("scenarioType.option2")) { // SUPRA-REGIONAL
+
+                final String supraRegional = accessSalix.getSupraRegionalString();
+                final List<SalixZone> list = SalixZone.parse(supraRegional);
+
+                final Map<DoubleRange, SalixScenario> rangeScenarioMap = new HashMap<>();
+                // make double range
+                for (int i = 0; i < list.size(); i++) {
+                    final SalixZone zone = list.get(i);
+                    final double upper = i < list.size() - 1 ? (zone.getUpperFromTo() - 0.0001) : zone.getUpperFromTo() + 0.0001;// "halboffenes Intervall
+
+                    final DoubleRange zonerange = new DoubleRange((double) zone.getLowerFromTo(), upper);
+                    final double salixValue = 666.;// TODO: calculate the salix value
+                    final SalixScenario salixscen = new SalixScenario(zone.getDwsplValue(), salixValue);
+
+                    rangeScenarioMap.put(zonerange, salixscen);
+                }
+
+                // make calculation
+                double currentKm = range.getMinimumDouble();
+                final double step = 0.1; // TODO: get from global setting?
+                while (currentKm < range.getMaximumDouble()) {
+                    final ResultRow rowSupraRegional = ResultRow.create(). //
+                            putValue(GeneralResultType.station, currentKm).//
+                            putValue(UInfoResultType.salixline, 28).//
+                            putValue(UInfoResultType.salix_delta_mw, 2);
+
+                    final SalixScenario scenarioCurrentKm = findScenarioByKm(currentKm, rangeScenarioMap);
+
+                    if (scenarioCurrentKm != null) { // should not happen, scenarioCurrentKm == null -> BUG
+                        rowSupraRegional.putValue(UInfoResultType.salix_line_scenario, scenarioCurrentKm.getSalixValue());
+                        rowSupraRegional.putValue(UInfoResultType.salix_line_scenario_dwspl, scenarioCurrentKm.getDwspl());
+                    }
+                    rows.add(rowSupraRegional);
+
+                    currentKm = currentKm + step;
+                }
+
+                result = new SalixLineCalculationSupraRegionalResult("Ergebnis 1 supra regional test", null, rows);
+
+            } else if (scenario.equals("scenarioType.option3")) { // HISTORICAL
+                row1.putValue(UInfoResultType.salixlinehist, 66).//
+                        putValue(UInfoResultType.salix_line_scenario_dwspl, 88);
+                rows.add(row1);
+                result = new SalixLineCalculationHistoricalResult("Ergebnis 1 historical test", null, rows);
+            }
+        }
         results.addResult(result, problems);
-
         return new CalculationResult(results, problems);
     }
+
+    private SalixScenario findScenarioByKm(final double km, final Map<DoubleRange, SalixScenario> rangeScenarioMap) {
+        final Iterator<DoubleRange> rangeIterator = rangeScenarioMap.keySet().iterator();
+        while (rangeIterator.hasNext()) {
+            final DoubleRange range = rangeIterator.next();
+            if (range.containsDouble(km + 0.0001)) {
+                return rangeScenarioMap.get(range);
+            }
+        }
+        return null;
+    }
 }
\ 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/uinfo/salix/SalixLineCalculationHistoricalResult.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,89 @@
+/** 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.uinfo.salix;
+
+import java.text.NumberFormat;
+import java.util.Collection;
+
+import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.IExportContext;
+import org.dive4elements.river.artifacts.common.ResultRow;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+final class SalixLineCalculationHistoricalResult extends SalixLineCalculationNoScenarioResult {
+
+    private static final long serialVersionUID = 1L;
+
+    public SalixLineCalculationHistoricalResult(final String label, final WstInfo wst, final Collection<ResultRow> rows) {
+        super(label, wst, rows);
+
+    }
+
+    @Override
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
+
+        final Collection<String> header = super.writeNoScenarioHeader(exportContextCSV);
+
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salixlinehist));
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salix_line_scenario_dwspl));
+
+        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
+    }
+
+    @Override
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
+        writeHistoricalViewCSVMetadata(exportContextCSV);
+        exportContextCSV.writeBlankLine();
+
+    }
+
+    @Override
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+
+        return formatRow(exportContextCSV, row);
+    }
+
+    private String[] formatRow(final IExportContext context, final ResultRow row) {
+
+        final Collection<String> lines = super.getNoScenarioFormat(row, context);
+
+        if (context instanceof ExportContextCSV) { // enum gespart - pdf-export hat ja nur die drei spalten
+            final NumberFormat formatter = ((ExportContextCSV) context).getSalixScenFormatter();
+
+            lines.add(context.formatRowValue(row, UInfoResultType.salixlinehist));
+            lines.add(context.formatRowValue(row, UInfoResultType.salix_line_scenario_dwspl));
+
+        }
+        return lines.toArray(new String[lines.size()]);
+    }
+
+    // TODO: move to historical class and delete here
+    private void writeHistoricalViewCSVMetadata(final ExportContextCSV exportContextCSV) {
+        final String main = "uinfo.export.csv.meta.header.salix.historical";
+        // "##Historische Betrachtung"
+        exportContextCSV.writeCSVMetaEntry(main);
+
+        final String mainSub = "uinfo.export.csv.meta.header.salix";
+        // "# Szenariotyp: "
+        exportContextCSV.writeCSVMetaEntry(mainSub + ".szenariotyp");
+        // "# Teilabschnitt: "
+        exportContextCSV.writeCSVMetaEntry(mainSub + ".teilabschnitt");
+
+        // "# Art des Zeitraums: "
+        exportContextCSV.writeCSVMetaEntry(main + ".zeitart");
+        // "# Historischer Zeitpunkt: "
+        exportContextCSV.writeCSVMetaEntry(main + ".zeitpunkt");
+    }
+}
\ 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/uinfo/salix/SalixLineCalculationNoScenarioResult.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,136 @@
+/** 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.uinfo.salix;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+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;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+class SalixLineCalculationNoScenarioResult extends AbstractCalculationExportableResult {
+
+    private static final long serialVersionUID = 1L;
+    private static final String JASPER_FILE = "/jasper/templates/uinfo.salixline.jrxml";
+
+    public SalixLineCalculationNoScenarioResult(final String label, final WstInfo wst, final Collection<ResultRow> rows) {
+        super(label, rows);
+    }
+
+    @Override
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
+        final Collection<String> header = writeNoScenarioHeader(exportContextCSV);
+        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
+
+    }
+
+    protected final Collection<String> writeNoScenarioHeader(final ExportContextCSV exportContextCSV) {
+        final Collection<String> header = new ArrayList<>();
+        header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station));
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salixline));
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salix_delta_mw));
+        return header;
+    }
+
+    @Override
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+
+        return formatRow(exportContextCSV, row);
+    }
+
+    @Override
+    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
+
+        return formatRow(exportContextPDF, row);
+    }
+
+    @Override
+    protected String getJasperFile() {
+
+        return this.JASPER_FILE;
+    }
+
+    @Override
+    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
+
+        /* additional column headings */
+        exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
+        exportContextPDF.addJRMetadata(source, "salix_line", UInfoResultType.salixline);
+        exportContextPDF.addJRMetadata(source, "salix_delta_mw", UInfoResultType.salix_delta_mw);
+
+    }
+
+    private String[] formatRow(final IExportContext context, final ResultRow row) {
+
+        final Collection<String> lines = getNoScenarioFormat(row, context);
+
+        // // ??
+        // // wenn "historisch" gewählt wurde, nur "historisch" anzeigen; sonst für jeden scen-wert ne neue Spalte und "hist"
+        // // ausblenden!...!..!!
+        // lines.add(context.formatRowValue(row, UInfoResultType.salixlinehist));
+        // lines.add(context.formatRowValue(row, UInfoResultType.salixlinescen));
+
+        return lines.toArray(new String[lines.size()]);
+    }
+
+    protected final Collection<String> getNoScenarioFormat(final ResultRow row, final IExportContext context) {
+        final Collection<String> lines = new ArrayList<>();
+        lines.add(context.formatRowValue(row, GeneralResultType.station));
+        lines.add(context.formatRowValue(row, UInfoResultType.salixline));
+        lines.add(context.formatRowValue(row, UInfoResultType.salix_delta_mw));
+
+        return lines;
+
+    }
+
+    protected final void writeRegionalCommonCSVMeta(final ExportContextCSV exportContextCSV) {
+        final String main = "uinfo.export.csv.meta.header.salix";
+        // "# Szenariotyp: "
+        exportContextCSV.writeCSVMetaEntry(main + ".szenariotyp");
+        // "# Teilabschnitt: "
+        exportContextCSV.writeCSVMetaEntry(main + ".teilabschnitt");
+        // "# Mittelwasserspiegellagenänderung: "
+        exportContextCSV.writeCSVMetaEntry(main + ".mwspiegellaenderung");
+    }
+
+    @Override
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
+        // do nothing. subclass may override
+
+    }
+
+    // private void writeHistoricalViewCSVMetadata(final ExportContextCSV exportContextCSV) {
+    // final String main = "uinfo.export.csv.meta.header.salix.historical";
+    // // "##Historische Betrachtung"
+    // exportContextCSV.writeCSVMetaEntry(main);
+    //
+    // final String mainSub = "uinfo.export.csv.meta.header.salix";
+    // // "# Szenariotyp: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".szenariotyp");
+    // // "# Teilabschnitt: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".teilabschnitt");
+    //
+    // // "# Art des Zeitraums: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitart");
+    // // "# Historischer Zeitpunkt: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitpunkt");
+    // }
+}
\ 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/uinfo/salix/SalixLineCalculationRegionalResult.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,113 @@
+/** 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.uinfo.salix;
+
+import java.text.NumberFormat;
+import java.util.Collection;
+import java.util.List;
+
+import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.IExportContext;
+import org.dive4elements.river.artifacts.common.ResultRow;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+final class SalixLineCalculationRegionalResult extends SalixLineCalculationNoScenarioResult {
+
+    private static final long serialVersionUID = 1L;
+    private final int[] scenarioValues;
+
+    public SalixLineCalculationRegionalResult(final String label, final WstInfo wst, final Collection<ResultRow> rows, final int[] scenarioValues) {
+        super(label, wst, rows);
+        this.scenarioValues = scenarioValues; // TODO: diese values müssen eigentlich nur ne anzahl sein, oder so. Ergibt sihc in der Berech
+    }
+
+    @Override
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
+
+        final Collection<String> header = super.writeNoScenarioHeader(exportContextCSV);
+
+        for (int i = 0; i < this.scenarioValues.length; i++) {
+            // index wurde verworfen, stattdessen 2 spalten
+
+            header.add(exportContextCSV.msg(SalixScenario.getScenarioValueHeader()) + " (" + (i + 1) + ")"); // index kann auch weg, war nur ne idee
+            header.add(exportContextCSV.msg(SalixScenario.getDwsplHeader()) + " (" + (i + 1) + ")");
+        }
+        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
+    }
+
+    @Override
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
+        writeRegionalEffectsCSVMetadata(exportContextCSV);
+        exportContextCSV.writeBlankLine();
+
+    }
+
+    @Override
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+
+        return formatRow(exportContextCSV, row);
+    }
+
+    private String[] formatRow(final IExportContext context, final ResultRow row) {
+
+        final Collection<String> lines = super.getNoScenarioFormat(row, context);
+
+        if (context instanceof ExportContextCSV) { // enum gespart - pdf-export hat ja nur die drei spalten
+            final NumberFormat formatter = ((ExportContextCSV) context).getSalixScenFormatter();
+            final List<SalixScenario> scenList = (List<SalixScenario>) row.getValue(UInfoResultType.customMultiRowColSalixRegionalValue_Dwspl);
+
+            for (final SalixScenario scenario : scenList) {
+                // scenario unused; index wurde ja verworfen, stattdessen 2 spalten
+                lines.add(scenario.getSalixValueFormatted(formatter));
+                lines.add(scenario.getDwsplFormatted());
+            }
+        }
+        return lines.toArray(new String[lines.size()]);
+    }
+
+    private void writeRegionalEffectsCSVMetadata(final ExportContextCSV exportContextCSV) {
+        final String main = "uinfo.export.csv.meta.header.salix.regional";
+        // "##Regional wirkende Eingriffe"
+        exportContextCSV.writeCSVMetaEntry(main);
+        writeRegionalCommonCSVMeta(exportContextCSV);
+    }
+
+    // TODO: move to SupraRegionalEffectsResult-Class; remove here
+    // private void writeExtendedRegionalEffectsCSVMetadata(final ExportContextCSV exportContextCSV) {
+    // final String main = "uinfo.export.csv.meta.header.salix.regionalextended";
+    // // "##Überregional wirkende Eingriffe"
+    // exportContextCSV.writeCSVMetaEntry(main);
+    //
+    // writeRegionalCommonCSVMeta(exportContextCSV);
+    // }
+
+    // TODO: move to historical class and delete here
+    // private void writeHistoricalViewCSVMetadata(final ExportContextCSV exportContextCSV) {
+    // final String main = "uinfo.export.csv.meta.header.salix.historical";
+    // // "##Historische Betrachtung"
+    // exportContextCSV.writeCSVMetaEntry(main);
+    //
+    // final String mainSub = "uinfo.export.csv.meta.header.salix";
+    // // "# Szenariotyp: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".szenariotyp");
+    // // "# Teilabschnitt: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".teilabschnitt");
+    //
+    // // "# Art des Zeitraums: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitart");
+    // // "# Historischer Zeitpunkt: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitpunkt");
+    // }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResult.java	Fri Jul 06 13:18:51 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +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.uinfo.salix;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-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;
-import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
-import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType;
-
-/**
- * @author Domenico Nardi Tironi
- */
-final class SalixLineCalculationResult extends AbstractCalculationExportableResult {
-
-    private static final long serialVersionUID = 1L;
-    private static final String JASPER_FILE = "/jasper/templates/uinfo.salixline.jrxml";
-
-    public SalixLineCalculationResult(final String label, final WstInfo wst, final Collection<ResultRow> rows) {
-        super(label, rows);
-    }
-
-    @Override
-    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
-
-        final Collection<String> header = new ArrayList<>(4);
-
-        header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station));
-        // header.add(msgUnit(SInfoResultType.flowdepth, SInfoResultType.flowdepth.getUnit()));
-
-        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salixline));
-        // wenn "historisch" gewählt wurde, nur "historisch" anzeigen; sonst für jeden scen-wert ne neue Spalte und "hist"
-        // ausblenden!...!..!!
-        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salixlinehist));
-        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salixlinescen));
-        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
-
-    }
-
-    @Override
-    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
-        writeRegionalEffectsCSVMetadata(exportContextCSV);
-        exportContextCSV.writeBlankLine();
-        writeExtendedRegionalEffectsCSVMetadata(exportContextCSV);
-        exportContextCSV.writeBlankLine();
-        writeHistoricalViewCSVMetadata(exportContextCSV);
-        exportContextCSV.writeBlankLine();
-
-    }
-
-    @Override
-    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
-
-        return formatRow(exportContextCSV, row);
-    }
-
-    @Override
-    protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) {
-
-        return formatRow(exportContextPDF, row);
-    }
-
-    @Override
-    protected String getJasperFile() {
-
-        return this.JASPER_FILE;
-    }
-
-    @Override
-    protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) {
-
-        /* additional column headings */
-        exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station);
-
-        exportContextPDF.addJRMetadata(source, "salix_line", UInfoResultType.salixline);
-        // wenn "historisch" gewählt wurde, nur "historisch" anzeigen; sonst für jeden scen-wert ne neue Spalte und "hist"
-        // ausblenden!...!..!!
-        exportContextPDF.addJRMetadata(source, "salix_line_hist", UInfoResultType.salixlinehist);
-        exportContextPDF.addJRMetadata(source, "salix_line_scen", UInfoResultType.salixlinescen);
-
-    }
-
-    private String[] formatRow(final IExportContext context, final ResultRow row) {
-
-        final Collection<String> lines = new ArrayList<>(3);
-
-        lines.add(context.formatRowValue(row, GeneralResultType.station));
-        lines.add(context.formatRowValue(row, UInfoResultType.salixline));
-
-        // wenn "historisch" gewählt wurde, nur "historisch" anzeigen; sonst für jeden scen-wert ne neue Spalte und "hist"
-        // ausblenden!...!..!!
-        lines.add(context.formatRowValue(row, UInfoResultType.salixlinehist));
-        lines.add(context.formatRowValue(row, UInfoResultType.salixlinescen));
-        return lines.toArray(new String[lines.size()]);
-    }
-
-    private void writeRegionalEffectsCSVMetadata(final ExportContextCSV exportContextCSV) {
-        final String main = "uinfo.export.csv.meta.header.salix.regional";
-        // "##Regional wirkende Eingriffe"
-        exportContextCSV.writeCSVMetaEntry(main);
-        writeRegionalCommonCSVMeta(exportContextCSV);
-    }
-
-    private void writeRegionalCommonCSVMeta(final ExportContextCSV exportContextCSV) {
-        final String main = "uinfo.export.csv.meta.header.salix";
-        // "# Szenariotyp: "
-        exportContextCSV.writeCSVMetaEntry(main + ".szenariotyp");
-        // "# Teilabschnitt: "
-        exportContextCSV.writeCSVMetaEntry(main + ".teilabschnitt");
-        // "# Mittelwasserspiegellagenänderung: "
-        exportContextCSV.writeCSVMetaEntry(main + ".mwspiegellaenderung");
-    }
-
-    private void writeExtendedRegionalEffectsCSVMetadata(final ExportContextCSV exportContextCSV) {
-        final String main = "uinfo.export.csv.meta.header.salix.regionalextended";
-        // "##Überregional wirkende Eingriffe"
-        exportContextCSV.writeCSVMetaEntry(main);
-
-        writeRegionalCommonCSVMeta(exportContextCSV);
-    }
-
-    private void writeHistoricalViewCSVMetadata(final ExportContextCSV exportContextCSV) {
-        final String main = "uinfo.export.csv.meta.header.salix.historical";
-        // "##Historische Betrachtung"
-        exportContextCSV.writeCSVMetaEntry(main);
-
-        final String mainSub = "uinfo.export.csv.meta.header.salix";
-        // "# Szenariotyp: "
-        exportContextCSV.writeCSVMetaEntry(mainSub + ".szenariotyp");
-        // "# Teilabschnitt: "
-        exportContextCSV.writeCSVMetaEntry(mainSub + ".teilabschnitt");
-
-        // "# Art des Zeitraums: "
-        exportContextCSV.writeCSVMetaEntry(main + ".zeitart");
-        // "# Historischer Zeitpunkt: "
-        exportContextCSV.writeCSVMetaEntry(main + ".zeitpunkt");
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResults.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationResults.java	Fri Jul 13 11:40:25 2018 +0200
@@ -17,7 +17,7 @@
  * @author Domenico Nardi Tironi
  *
  */
-final class SalixLineCalculationResults extends AbstractCalculationResults<SalixLineCalculationResult> {
+final class SalixLineCalculationResults extends AbstractCalculationResults<SalixLineCalculationNoScenarioResult> {
 
     private static final long serialVersionUID = 1L;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculationSupraRegionalResult.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,97 @@
+/** 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.uinfo.salix;
+
+import java.text.NumberFormat;
+import java.util.Collection;
+
+import org.dive4elements.river.artifacts.common.ExportContextCSV;
+import org.dive4elements.river.artifacts.common.IExportContext;
+import org.dive4elements.river.artifacts.common.ResultRow;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.artifacts.uinfo.commons.UInfoResultType;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+final class SalixLineCalculationSupraRegionalResult extends SalixLineCalculationNoScenarioResult {
+
+    private static final long serialVersionUID = 1L;
+
+    public SalixLineCalculationSupraRegionalResult(final String label, final WstInfo wst, final Collection<ResultRow> rows) {
+        super(label, wst, rows);
+
+    }
+
+    @Override
+    public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) {
+
+        final Collection<String> header = super.writeNoScenarioHeader(exportContextCSV);
+
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salix_line_scenario));
+        header.add(exportContextCSV.formatCsvHeader(UInfoResultType.salix_line_scenario_dwspl));
+
+        exportContextCSV.writeCSVLine(header.toArray(new String[header.size()]));
+    }
+
+    @Override
+    protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) {
+        writeExtendedRegionalEffectsCSVMetadata(exportContextCSV);
+        exportContextCSV.writeBlankLine();
+
+    }
+
+    @Override
+    protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) {
+
+        return formatRow(exportContextCSV, row);
+    }
+
+    private String[] formatRow(final IExportContext context, final ResultRow row) {
+
+        final Collection<String> lines = super.getNoScenarioFormat(row, context);
+
+        if (context instanceof ExportContextCSV) { // enum gespart - pdf-export hat ja nur die drei spalten
+            final NumberFormat formatter = ((ExportContextCSV) context).getSalixScenFormatter();
+
+            lines.add(context.formatRowValue(row, UInfoResultType.salix_line_scenario));
+            lines.add(context.formatRowValue(row, UInfoResultType.salix_line_scenario_dwspl));
+
+        }
+        return lines.toArray(new String[lines.size()]);
+    }
+
+    private void writeExtendedRegionalEffectsCSVMetadata(final ExportContextCSV exportContextCSV) {
+        final String main = "uinfo.export.csv.meta.header.salix.regionalextended";
+        // "##Überregional wirkende Eingriffe"
+        exportContextCSV.writeCSVMetaEntry(main);
+
+        writeRegionalCommonCSVMeta(exportContextCSV);
+    }
+
+    // TODO: move to historical class and delete here
+    // private void writeHistoricalViewCSVMetadata(final ExportContextCSV exportContextCSV) {
+    // final String main = "uinfo.export.csv.meta.header.salix.historical";
+    // // "##Historische Betrachtung"
+    // exportContextCSV.writeCSVMetaEntry(main);
+    //
+    // final String mainSub = "uinfo.export.csv.meta.header.salix";
+    // // "# Szenariotyp: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".szenariotyp");
+    // // "# Teilabschnitt: "
+    // exportContextCSV.writeCSVMetaEntry(mainSub + ".teilabschnitt");
+    //
+    // // "# Art des Zeitraums: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitart");
+    // // "# Historischer Zeitpunkt: "
+    // exportContextCSV.writeCSVMetaEntry(main + ".zeitpunkt");
+    // }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineExporter.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineExporter.java	Fri Jul 13 11:40:25 2018 +0200
@@ -12,24 +12,18 @@
 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.MetaAndTableJRDataSource;
 
 /**
  * @author Domenico Nardi Tironi
  *
  */
-public class SalixLineExporter extends AbstractCommonExporter<SalixLineCalculationResult, SalixLineCalculationResults> {
+public class SalixLineExporter extends AbstractCommonExporter<SalixLineCalculationNoScenarioResult, SalixLineCalculationResults> {
 
     @Override
     protected void writeCSVGlobalMetadata(final ExportContextCSV exportContextCSV, final SalixLineCalculationResults results) {
         /* write as csv */
-        exportContextCSV.writeCSVGlobalMetadataDefaults(); // ggf auslagern innerhalb dieser Klasse
-
-        // break line ?
-
-        // "# Höhensystem des Flusses: "
-        exportContextCSV.writeCSVMetaEntry(I18NStrings.CSV_META_HEIGHT_UNIT_RIVER, results.getRiver().getWstUnit());
+        exportContextCSV.writeCSVGlobalMetadataDefaults();
 
         // Add Auswerter, Bezugspegel, Jahr/Zeitraum der Wasserspiegellage
 
@@ -39,9 +33,7 @@
         exportContextCSV.writeCSVMetaEntry("uinfo.export.salix_line.csv.meta.header.waterlevel.gauge", "wst.getGauge()");
 
         // "# Jahr/Zeitraum der Wasserspiegellage: "
-        // final int year = wst.getYear();
-        // if (year > 0)
-        exportContextCSV.writeCSVMetaEntry("uinfo.export.salix_line.csv.meta.header.waterlevel.year", "Integer.toString(year)");
+        exportContextCSV.writeCSVMetaEntry("uinfo.export.salix_line.csv.meta.header.waterlevel.year", "TODO...");
 
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineState.java	Fri Jul 13 11:40:25 2018 +0200
@@ -77,7 +77,7 @@
 
         final SalixLineCalculationResults results = (SalixLineCalculationResults) res.getData();
 
-        final List<SalixLineCalculationResult> resultList = results.getResults();
+        final List<SalixLineCalculationNoScenarioResult> resultList = results.getResults();
 
         if (!resultList.isEmpty()) {
             final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixScenario.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,55 @@
+/** 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.uinfo.salix;
+
+import java.io.Serializable;
+import java.text.NumberFormat;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class SalixScenario implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private final double salix_value;
+    private final int dwspl;
+
+    public SalixScenario(final int scen_val, final double salix_value) {
+        this.dwspl = scen_val;
+        this.salix_value = salix_value;
+    }
+
+    public double getSalixValue() {
+        return this.salix_value;
+    }
+
+    public int getDwspl() {
+        return this.dwspl;
+    }
+
+    public String getDwsplFormatted() {
+        return String.valueOf(this.dwspl);
+    }
+
+    public String getSalixValueFormatted(final NumberFormat formatter) {
+        return formatter.format(this.salix_value);
+    }
+
+    public static final String getScenarioValueHeader() {
+        return "uinfo.export.salix_line.csv.header.scenario";
+    }
+
+    public static final String getDwsplHeader() {
+        return "uinfo.export.salix_line.csv.header.scenario_dwspl";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixZone.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,176 @@
+/** 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.uinfo.salix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class SalixZone implements Comparable<SalixZone> {
+
+    // IMMER ABGLEICHEN Server Client SalixZone.java
+    private static final String TABLE_CELL_SEPARATOR = "TABLE_CELL_SEPARATOR";
+    private static final String TABLE_ROW_SEPARATOR = "TABLE_ROW_SEPARATOR";
+    private final int dwsplValue;
+    private final double fromKm;
+    private final double toKm;
+
+    private final static double DELTA = 0.0001;
+
+    public static List<SalixZone> parse(final String zonesRaw) {
+        final List<SalixZone> resultList = new ArrayList<>();
+
+        final List<String[]> results = new ArrayList<>();
+        if (zonesRaw.contains(TABLE_ROW_SEPARATOR)) {
+            final String[] rows = zonesRaw.split(TABLE_ROW_SEPARATOR);
+            for (final String row : rows) {
+                if (row.contains(TABLE_CELL_SEPARATOR)) {
+                    final String[] result = row.split(TABLE_CELL_SEPARATOR);
+                    results.add(result);
+                }
+            }
+        }
+        for (final String[] zone : results) {
+            final SalixZone helper = new SalixZone(Integer.valueOf(zone[0]), Double.valueOf(zone[1]), Double.valueOf(zone[2]));
+            resultList.add(helper);
+        }
+        return resultList;
+    }
+
+    public static SalixZone createFromTableEntry(final String dwspl, final String from, final String to) {
+        return new SalixZone(Integer.valueOf(dwspl), Double.valueOf(from), Double.valueOf(to)); // Error-Handling?
+    }
+
+    private SalixZone(final int dwsplValue, final double fromKm, final double toKm) {
+        this.dwsplValue = dwsplValue;
+        this.fromKm = fromKm;
+        this.toKm = toKm;
+    }
+
+    public Double getToKm() {
+        return this.toKm;
+    }
+
+    public int getDwsplValue() {
+        return this.dwsplValue;
+    }
+
+    public Double getFromKm() {
+        return this.fromKm;
+    }
+
+    public static final String parseListToDataString(final List<SalixZone> list) {
+
+        java.util.Collections.sort(list);
+        final StringBuilder builder = new StringBuilder();
+        for (final SalixZone zone : list) {
+            builder.append(zone.getDwsplValue());
+            builder.append(TABLE_CELL_SEPARATOR);
+            builder.append(zone.getFromKm());
+            builder.append(TABLE_CELL_SEPARATOR);
+            builder.append(zone.getToKm());
+            builder.append(TABLE_ROW_SEPARATOR);
+        }
+        return builder.toString();
+    }
+
+    public static final boolean zonesAreOverlapping(final List<SalixZone> list) {
+        for (final SalixZone zone : list) {
+            for (final SalixZone zoneOther : list) {
+                if (zone != zoneOther) {
+                    final boolean overlaps = zone.overlaps(zoneOther);
+                    if (overlaps) {
+                        return overlaps; // cancel. only one zone has to overlap
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public static final boolean hasGaps(final List<SalixZone> list, final double lower, final double upper) {
+
+        if (((upper - lower) > DELTA) && list.size() == 0)
+            return true;
+
+        final TreeSet<SalixZone> treeList = new TreeSet<>();
+        treeList.addAll(list);
+        double lowerCompare = lower + DELTA;
+        for (final SalixZone zone : treeList) {
+            if ((zone.getUpperFromTo() - zone.getLowerFromTo()) > DELTA) {
+                if (zone.getLowerFromTo() > lowerCompare) {
+                    return true;
+                }
+                lowerCompare = zone.getUpperFromTo() + DELTA;
+            }
+        }
+        if ((lowerCompare + DELTA) < upper)
+            return true; // am Ende nicht geschlossen
+
+        return false;
+    }
+
+    public Double getLowerFromTo() {
+        return this.fromKm < this.toKm ? this.fromKm : this.toKm; // Math. is forbidden :-(
+    }
+
+    public Double getUpperFromTo() {
+        return this.fromKm > this.toKm ? this.fromKm : this.toKm;// Math. is forbidden :-(
+    }
+
+    private boolean overlaps(final SalixZone otherZone) {
+        final double otherLower = otherZone.getLowerFromTo();
+        final double otherUpper = otherZone.getUpperFromTo();
+
+        final double upper = getUpperFromTo();
+        final double lower = getLowerFromTo();
+        final double otherSchwerpunkt = (otherLower + otherUpper) / 2;
+        if ((otherUpper < upper && otherUpper > lower)) {
+            return true;
+        } else if (otherLower > lower && otherLower < upper) {
+            return true;
+        } else if (otherSchwerpunkt > (lower - DELTA) && otherSchwerpunkt < (upper + DELTA)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int compareTo(final SalixZone o) {
+        final int basicCompare = this.getLowerFromTo().compareTo(o.getLowerFromTo());
+        if (basicCompare == 0) {
+            return 1; // necessary for the treeSet!
+        }
+        return basicCompare;
+    }
+
+    public static boolean isValidAnschlussRange(final double fromTest, final double toTest, final List<SalixZone> list, final double minKm) {
+        final SalixZone zone = new SalixZone(0, fromTest, toTest);
+        final double lower = zone.getLowerFromTo();
+        final double anschluss = getAnschluss(list, minKm);
+        final double differenceAbs = (lower - anschluss) > 0 ? (lower - anschluss) : (anschluss - lower); // no Math.abs allowed :-(
+        if (differenceAbs > DELTA) {
+            return false;
+        }
+        return true;
+    }
+
+    private static double getAnschluss(final List<SalixZone> list, final double minKm) {
+        if (list.size() > 0) {
+            return list.get(list.size() - 1).getUpperFromTo();
+        }
+        return minKm;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SupraRegionalTableState.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,54 @@
+/** 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.uinfo.salix;
+
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.access.RangeAccess;
+import org.dive4elements.river.artifacts.states.DefaultState;
+import org.w3c.dom.Element;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public class SupraRegionalTableState extends DefaultState {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected String getUIProvider() {
+        return "uinfo.salix.supraregional.table";
+    }
+
+    @Override
+    protected Element[] createItems(final ElementCreator cr, final Artifact artifact, final String name, final CallContext context) {
+        final String datakey = "supraregional_table";
+        if (name.equals(datakey)) {
+
+            final D4EArtifact flys = (D4EArtifact) artifact;
+            final String s = flys.getDataAsString(datakey);
+
+            final RangeAccess ra = new RangeAccess((D4EArtifact) artifact);
+
+            final Element item = createItem(cr, new String[] { "salix_zones", s });
+            final Element min = createItem(cr, new String[] { "salix_zones_min", new Double(ra.getFrom()).toString() });
+
+            final Element max = createItem(cr, new String[] { "salix_zones_max", new Double(ra.getTo()).toString() });
+
+            return new Element[] { min, max, item };
+
+        }
+
+        return new Element[] {};
+    }
+
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java	Fri Jul 13 11:40:25 2018 +0200
@@ -721,7 +721,7 @@
         return Resources.getMsg(this.context.getMeta(), key, key);
     }
 
-    public final String msg(final String key, final String def, final Object[] args) {
+    public final String msg(final String key, final String def, final Object... args) {
         return Resources.getMsg(this.context.getMeta(), key, def, args);
     }
 
--- a/artifacts/src/main/resources/messages.properties	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Fri Jul 13 11:40:25 2018 +0200
@@ -76,6 +76,7 @@
 state.minfo.m3_per_a = m\u00b3/a
 
 state.uinfo.vegetation_zones.table = Einteilung der Vegetationszonen und \u00dcberflutungsdauern (\u00dcFD)
+state.uinfo.salix.supraregional = \u00dcberregional wirkende Eingriffe
 
 state.uinfo.year_totalepoch = Year/Gesamter Zeitraum
 state.uinfo.year_epoch = Year/Epoch
@@ -1087,10 +1088,13 @@
 mainvalue.w.description = Wasserstand/Wasserspiegel-lage ({0})
 mainvalue.duration = \u00dcberflutungsdauer
 mainvalue.duration.description = \u00dcberflutungsdauer ({0})
+state.uinfo.salix.historical.km_range_part = Ausgewertete Strecke
+uinfo.salix.sounding= Peilung
 uinfo.salix.soundings= Soundings
+uinfo.export.salix_line.csv.header.scenario_dwspl = \u0394MW [cm]
+uinfo.export.salix_line.csv.header.scenario = Salix-Linie_Szenario [m]
 uinfo.export.salix_line.csv.header.salix_line = Salix-Linie [m]
-uinfo.export.salix_line.csv.header.delta_mw =  (MW-MNW)x(-1) [m]
-uinfo.export.salix_line.csv.header.scen =  Salix-Linie [m] Szenario dMW={0} cm
+uinfo.export.salix_line.csv.header.delta_mw =  (MW-MNW)x(-1) [m] 
 uinfo.export.salix_line.csv.header.hist =  Salix-Linie [m] historisch
 uinfo.export.salix_line.csv.meta.header.evaluator = # Auswerter: {0}
 uinfo.export.salix_line.csv.meta.header.waterlevel.year = # Jahr/Zeitraum der Wasserspiegellage: {0}
@@ -1149,6 +1153,10 @@
 sinfo.chart.flood_duration.height.section.title = H\u00f6he Infrastrukturen BWaStr
 sinfo_facet_flood_height = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr
 sinfo_facet_flood_height.description = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr ({0})
+sinfo.chart.flood_duration.curve.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
+sinfo.chart.flood_duration.curve.xaxis.label = \u00dcberflutungsdauer [d/a]
+sinfo.chart.flood_duration.curve.w = Wasserstandsdauerlinie
+sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixinganalysis
--- a/artifacts/src/main/resources/messages_de.properties	Fri Jul 06 13:18:51 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Fri Jul 13 11:40:25 2018 +0200
@@ -76,6 +76,7 @@
 state.minfo.m3_per_a = m\u00b3/a
 
 state.uinfo.vegetation_zones.table = Einteilung der Vegetationszonen und \u00dcberflutungsdauern (\u00dcFD)
+state.uinfo.salix.supraregional = \u00dcberregional wirkende Eingriffe
 
 state.uinfo.year_totalepoch = Jahr/Gesamter Zeitraum
 state.uinfo.year_epoch = Jahr/Epoche
@@ -1087,10 +1088,13 @@
 mainvalue.w.description = Wasserstand/Wasserspiegel-lage ({0})
 mainvalue.duration = \u00dcberflutungsdauer
 mainvalue.duration.description = \u00dcberflutungsdauer ({0})
+state.uinfo.salix.historical.km_range_part = Ausgewertete Strecke
+uinfo.salix.sounding= Peilung
 uinfo.salix.soundings= Peilungen
+uinfo.export.salix_line.csv.header.scenario_dwspl = \u0394MW [cm]
+uinfo.export.salix_line.csv.header.scenario = Salix-Linie_Szenario [m]
 uinfo.export.salix_line.csv.header.salix_line = Salix-Linie [m]
-uinfo.export.salix_line.csv.header.delta_mw =  (MW-MNW)x(-1) [m]
-uinfo.export.salix_line.csv.header.scen =  Salix-Linie [m] Szenario dMW={0} cm
+uinfo.export.salix_line.csv.header.delta_mw =  (MW-MNW)x(-1) [m] 
 uinfo.export.salix_line.csv.header.hist =  Salix-Linie [m] historisch
 uinfo.export.salix_line.csv.meta.header.evaluator = # Auswerter: {0}
 uinfo.export.salix_line.csv.meta.header.waterlevel.year = # Jahr/Zeitraum der Wasserspiegellage: {0}
@@ -1149,6 +1153,10 @@
 sinfo.chart.flood_duration.height.section.title = H\u00f6he Infrastrukturen BWaStr
 sinfo_facet_flood_height = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr
 sinfo_facet_flood_height.description = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr ({0})
+sinfo.chart.flood_duration.curve.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
+sinfo.chart.flood_duration.curve.xaxis.label = \u00dcberflutungsdauer [d/a]
+sinfo.chart.flood_duration.curve.w = Wasserstandsdauerlinie
+sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixierungsanalyse
--- a/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Fri Jul 13 11:40:25 2018 +0200
@@ -9,6 +9,7 @@
 package org.dive4elements.river.model;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.persistence.Column;
@@ -207,11 +208,8 @@
     public static List<BedHeight> getBedHeights(final River river, final double kmLo, final double kmHi) {
         final Session session = SessionHolder.HOLDER.get();
 
-        final Query query = session.createQuery("from BedHeight"
-                + " where river=:river"
-                + " and id in (select bedHeight.id from BedHeightValue"
-                + " where station between :kmfrom and :kmto"
-                + " group by bedHeight.id)");
+        final Query query = session.createQuery("from BedHeight" + " where river=:river" + " and id in (select bedHeight.id from BedHeightValue"
+                + " where station between :kmfrom and :kmto" + " group by bedHeight.id)");
 
         query.setParameter("river", river);
         query.setParameter("kmfrom", kmLo);
@@ -238,11 +236,8 @@
 
         final Session session = SessionHolder.HOLDER.get();
 
-        final Query query = session.createQuery("FROM BedHeight"
-                + " WHERE (TRIM(description)=:description) AND river=:river"
-                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue"
-                + " WHERE station BETWEEN :kmfrom AND :kmto"
-                + " GROUP BY bedHeight.id)");
+        final Query query = session.createQuery("FROM BedHeight" + " WHERE (TRIM(description)=:description) AND river=:river"
+                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
         query.setParameter("river", river);
         query.setParameter("description", description);
         query.setParameter("kmfrom", startKm);
@@ -252,4 +247,78 @@
 
         return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
     }
+
+    public static List<BedHeight> getBedHeightEpochs(final River river, final double startKm, final double endKm) {
+
+        final Session session = SessionHolder.HOLDER.get();
+        final String description = "epoch";
+        final Query query = session.createQuery("FROM BedHeight" + " WHERE lower(description) LIKE :description AND " + "river=:river"
+                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
+        query.setParameter("river", river);
+        query.setParameter("description", "%" + description + "%");
+        query.setParameter("kmfrom", startKm);
+        query.setParameter("kmto", endKm);
+
+        final List<BedHeight> singles = query.list();
+
+        return ((singles != null) && !singles.isEmpty()) ? singles : null;
+    }
+
+    public static List<BedHeight> getBedHeightYear(final River river, final double startKm, final double endKm) {
+
+        final Session session = SessionHolder.HOLDER.get();
+        final String description = "epoch";
+        final Query query = session.createQuery("FROM BedHeight" + " WHERE lower(description) NOT LIKE :description AND " + "river=:river"
+                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
+        query.setParameter("river", river);
+        query.setParameter("description", "%" + description + "%");
+        query.setParameter("kmfrom", startKm);
+        query.setParameter("kmto", endKm);
+
+        final List<BedHeight> singles = query.list();
+
+        return ((singles != null) && !singles.isEmpty()) ? singles : null;
+    }
+
+    public static Range getRangeFromBedHeights(final BedHeight bh) {
+        final List<Range> ranges = new ArrayList<>();
+
+        final Session session = SessionHolder.HOLDER.get();
+
+        final Query query = session.createQuery("FROM Range" + " WHERE id=:range_id)");
+        query.setParameter("range_id", bh.getRange().getId());
+
+        final List<Range> singles = query.list();
+
+        return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
+    }
+
+    public static List<BedHeight> getBedHeightYearEpoch(final boolean isEpoch, final Integer year, final River river, final double lowerKm,
+            final double upperKm) {
+
+        final Session session = SessionHolder.HOLDER.get();
+        final String description = "epoch";
+
+        final StringBuilder builder = new StringBuilder();
+        builder.append("FROM BedHeight");
+        if (isEpoch) {
+            builder.append(" WHERE lower(description) LIKE :description ");
+        } else {
+            builder.append(" WHERE lower(description) NOT LIKE :description ");
+        }
+        builder.append(" AND year =:year");
+
+        builder.append(
+                " AND river=:river  AND id IN (SELECT bedHeight.id FROM BedHeightValue   WHERE station BETWEEN :kmfrom AND :kmto  GROUP BY bedHeight.id )");
+        final Query query = session.createQuery(builder.toString());
+        query.setParameter("river", river);
+        query.setParameter("year", year);
+        query.setParameter("description", "%" + description + "%");
+        query.setParameter("kmfrom", lowerKm);
+        query.setParameter("kmto", upperKm);
+
+        final List<BedHeight> singles = query.list();
+
+        return ((singles != null) && !singles.isEmpty()) ? singles : null;
+    }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Fri Jul 13 11:40:25 2018 +0200
@@ -1556,4 +1556,22 @@
     String sinfo_sounding_waterlevel_select_waterlevel();
 
     String sinfo_deactivate_intelligent_datacord();
+
+    String sinfo_floodduration_curve();
+
+    String uinfo_salix_dmwspl_short();
+
+    String uinfo_salix_invalid_double();
+
+    String uinfo_salix_km_limit_exceed();
+
+    String uinfo_salix_km_overlap();
+
+    String uinfo_salix_km_has_gaps();
+
+    String uinfo_salix_km_anschluss();
+
+    String uinfo_salix_input_complete();
+
+    String common_input_hint_year();
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Fri Jul 13 11:40:25 2018 +0200
@@ -89,6 +89,7 @@
 sedimentload_ls = Sediment Load
 welcome = Welcome to Flusshydrologische Software
 welcome_open_or_create = Please open a project from the project list or create a
+common_input_hint_year = YYYY
 
 # Header images
 flysLogo = images/flys_logo.gif
@@ -813,10 +814,12 @@
 sinfo_collisions = Grundber\u00fchrungen
 sinfo_collision = Grundber\u00fchrungen
 
-sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr
-sinfo_flood_height = H\u00f6he Infrastruktur BWaStr
+sinfo_flood_duration = \u00dcberflutungsdauer Infrastrukturen BWaStr
+sinfo_flood_height = H\u00f6he Infrastrukturen BWaStr
+sinfo_floodduration_curve = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
 
 uinfo = U-INFO
+uinfo_salix_dmwspl_short = \u0394MW [cm]
 uinfo_inundation_duration_export = \u00dcberflutungsdauern Export
 uinfo_salix_line_export = Salix-Linie Export
 uinfo_vegetation_zones_export = Vegetationszonen Export
@@ -829,6 +832,12 @@
 uinfo_vegetation_zones_validation_range = Werte m\u00fcssen zwischen 0 und 365 liegen.
 uinfo_vegetation_zones_validation_from_greater_to = Der Wert f\u00fcr "\u00dcfd von" muss kleiner als "\u00dcfd bis".
 uinfo_vegetation_zones_invalid_integer = Nur Ganzzahlen erlaubt.
+uinfo_salix_invalid_double = Nur Zahlen erlaubt.
+uinfo_salix_km_limit_exceed = Die Zahl ist au\u00dferhalb des g\u00fcltigen km-Bereichs.
+uinfo_salix_km_overlap = Km-Bereiche \u00fcberlappen.
+uinfo_salix_km_has_gaps = Der Km-Bereich ist nicht vollst. belegt.
+uinfo_salix_km_anschluss = Der eingegebene Bereich schlie\u00dft nicht an den letzten Wert an.
+uinfo_salix_input_complete = Die gesamte Strecke ist bereits mit Werten belegt.
 
 bundu = Betrieb und Unterhaltung 
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Fri Jul 13 11:40:25 2018 +0200
@@ -89,6 +89,7 @@
 sedimentload_ls = Sediment Fracht
 welcome = Willkommen bei der Flusshydrologischen Software
 welcome_open_or_create = Bitte \u00f6ffnen Sie ein bestehendes Projekt aus der Projektliste oder erstellen Sie ein
+common_input_hint_year = JJJJ
 
 # Header images
 flysLogo = images/flys_logo.gif
@@ -813,10 +814,12 @@
 sinfo_collisions = Grundber\u00fchrungen
 sinfo_collision = Grundber\u00fchrungen
 
-sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr
-sinfo_flood_height = H\u00f6he Infrastruktur BWaStr
+sinfo_flood_duration = \u00dcberflutungsdauer Infrastrukturen BWaStr
+sinfo_flood_height = H\u00f6he Infrastrukturen BWaStr
+sinfo_floodduration_curve = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
 
 uinfo = U-INFO
+uinfo_salix_dmwspl_short = \u0394MW [cm]
 uinfo_inundation_duration_export = \u00dcberflutungsdauern Export
 uinfo_salix_line_export = Salix-Linie Export
 uinfo_vegetation_zones_export = Vegetationszonen Export
@@ -829,6 +832,12 @@
 uinfo_vegetation_zones_validation_range = Werte m\u00fcssen zwischen 0 und 365 liegen.
 uinfo_vegetation_zones_validation_from_greater_to = Der Wert f\u00fcr "\u00dcfd von" muss kleiner als "\u00dcfd bis".
 uinfo_vegetation_zones_invalid_integer = Nur Ganzzahlen erlaubt.
+uinfo_salix_invalid_double = Nur Zahlen erlaubt.
+uinfo_salix_km_limit_exceed = Die Zahl ist au\u00dferhalb des g\u00fcltigen km-Bereichs.
+uinfo_salix_km_overlap = Km-Bereiche \u00fcberlappen.
+uinfo_salix_km_has_gaps = Der Km-Bereich ist nicht vollst. belegt.
+uinfo_salix_km_anschluss = Der eingegebene Bereich schlie\u00dft nicht an den letzten Wert an.
+uinfo_salix_input_complete = Die gesamte Strecke ist bereits mit Werten belegt.
 
 bundu = Betrieb und Unterhaltung
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractSingleItemPanel.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractSingleItemPanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -226,20 +226,23 @@
 
         switch (this.type) {
         case multi:
-
-            final String[] sValues = sValue.trim().split(" ");
-            for (final String value : sValues) {
-                errors.addAll(this.validateSingleInput(value));
+            if (sValue != null) {
+                final String[] sValues = sValue.trim().split(" ");
+                for (final String value : sValues) {
+                    errors.addAll(this.validateSingleInput(value));
+                }
             }
             break;
         case limit5:
-            final String[] values = sValue.trim().split(" ");
-            if (values.length > 5) {
-                errors.add(this.MSG.error_limit_exceeded_salix());// TODO generalize if needed
-            }
-            for (int i = 0; i < values.length; i++) {
-                if (i < 5)
-                    errors.addAll(this.validateNumber(values[i]));
+            if (sValue != null) {
+                final String[] values = sValue.trim().split(" ");
+                if (values.length > 5) {
+                    errors.add(this.MSG.error_limit_exceeded_salix());// TODO generalize if needed
+                }
+                for (int i = 0; i < values.length; i++) {
+                    if (i < 5)
+                        errors.addAll(this.validateNumber(values[i]));
+                }
             }
             break;
         case single:
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java	Fri Jul 13 11:40:25 2018 +0200
@@ -331,5 +331,11 @@
      * @return the selected data.
      */
     protected abstract Data[] getData();
+
+    protected String getRiverName() {
+        final ArtifactDescription adescr = this.artifact.getArtifactDescription();
+        return adescr.getRiver();
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistanceOnlyPartHistoricalPanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,61 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.client.client.ui;
+
+import java.util.List;
+
+import org.dive4elements.river.client.shared.model.Data;
+import org.dive4elements.river.client.shared.model.DataList;
+
+import com.smartgwt.client.widgets.Canvas;
+
+public class DistanceOnlyPartHistoricalPanel extends DistanceOnlyPartPanel {
+
+    private static final long serialVersionUID = 1L;
+    private List<String> validInputs;
+
+    @Override
+    protected void initHelperPanel(final DataList data) {
+        final FromToTableHelperPanel helper = new FromToTableHelperPanel(data, "bedheights_for_part", this.MSG, null, null);
+        final Canvas table = helper.getTable();
+        this.validInputs = helper.getKeycolEntries();
+
+        this.helperContainer.addMember(table);
+
+    }
+
+    @Override
+    protected void initMinMaxValues(final DataList data) {
+        try {
+            for (final Data item : data.getAll()) {
+                if (item.getLabel().equals("ld_from_part"))// misuse ld_from_part for max container
+                    this.min = Double.valueOf(item.getItems()[0].getStringValue());
+
+                if (item.getLabel().equals("ld_to_part"))// misuse ld_to_part for max container
+                    this.max = Double.valueOf(item.getItems()[0].getStringValue());
+            }
+        }
+        catch (final NumberFormatException nfe) {
+            this.min = -Double.MAX_VALUE;
+            this.max = Double.MAX_VALUE;
+        }
+    }
+
+    @Override
+    protected void initDefaultFrom(final DataList data) {
+        final double from = (this.min < -99999.) ? 0 : this.min;
+        this.distancePanel.setFrom(from);
+    }
+
+    @Override
+    protected void initDefaultTo(final DataList data) {
+        final double to = (this.max > 99999.) ? 0 : this.max;
+        this.distancePanel.setTo(to);
+    }
+}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -9,18 +9,9 @@
 package org.dive4elements.river.client.client.ui;
 
 import java.util.ArrayList;
-import java.util.LinkedHashMap;
 import java.util.List;
 
-import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.FLYSConstants;
-import org.dive4elements.river.client.client.event.FilterHandler;
-import org.dive4elements.river.client.client.event.RangeFilterEvent;
-import org.dive4elements.river.client.client.event.StringFilterEvent;
-import org.dive4elements.river.client.client.ui.range.DistanceInfoDataSource;
-import org.dive4elements.river.client.client.ui.range.LocationsTable;
-import org.dive4elements.river.client.client.ui.range.RangeTable;
-import org.dive4elements.river.client.shared.model.ArtifactDescription;
 import org.dive4elements.river.client.shared.model.Data;
 import org.dive4elements.river.client.shared.model.DataItem;
 import org.dive4elements.river.client.shared.model.DataList;
@@ -29,34 +20,22 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.NumberFormat;
-import com.smartgwt.client.data.AdvancedCriteria;
-import com.smartgwt.client.data.Criteria;
-import com.smartgwt.client.data.Criterion;
 import com.smartgwt.client.data.Record;
-import com.smartgwt.client.types.Alignment;
-import com.smartgwt.client.types.OperatorId;
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Label;
-import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.SelectItem;
 import com.smartgwt.client.widgets.form.fields.StaticTextItem;
 import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
 import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
-import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
-import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
 import com.smartgwt.client.widgets.grid.ListGrid;
 import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
 import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
-import com.smartgwt.client.widgets.tab.Tab;
 import com.smartgwt.client.widgets.tab.TabSet;
-import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
-import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
 
 /** Panel to allow input of distance for calculation range. */
-public class DistancePanel extends AbstractUIProvider implements BlurHandler, FilterHandler {
+public class DistancePanel extends AbstractUIProvider implements BlurHandler {
 
     private static final long serialVersionUID = -883142387908664588L;
 
@@ -68,8 +47,8 @@
 
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
-    protected RangeTable distancesTable;
-    protected LocationsTable locationsTable;
+    // protected RangeTable distancesTable;
+    // protected LocationsTable locationsTable;
 
     protected DoubleRangePanel distancePanel;
 
@@ -110,7 +89,7 @@
 
         initMinMaxValues(data);
         initDefaultValues(data);
-        initHelperPanel();
+        initHelperPanel(data);
 
         return layout;
     }
@@ -299,11 +278,6 @@
         return new DefaultData(field, null, null, new DataItem[] { item });
     }
 
-    @Override
-    public void onBlur(final BlurEvent event) {
-        this.distancePanel.validateForm();
-    }
-
     protected void initMinMaxValues(final DataList data) {
         final Data f = getData(data.getAll(), getLowerField());
         final Data t = getData(data.getAll(), getUpperField());
@@ -392,20 +366,11 @@
         return Double.valueOf(defValue);
     }
 
-    protected void initHelperPanel() {
-        this.distancesTable = new RangeTable();
-        this.locationsTable = new LocationsTable();
+    protected void initHelperPanel(final DataList data) {
 
-        final Config config = Config.getInstance();
-        final String url = config.getServerUrl();
-        final String river = getRiverName();
+        final DistancePanelInputHelper helper = new DistancePanelInputHelper(this.MSG, this.helperContainer, this.getRiverName());
 
-        this.distancesTable.setAutoFetchData(true);
-        this.locationsTable.setAutoFetchData(true);
-        this.distancesTable.setDataSource(new DistanceInfoDataSource(url, river, "distances"));
-        this.locationsTable.setDataSource(new DistanceInfoDataSource(url, river, "locations"));
-
-        this.distancesTable.addRecordClickHandler(new RecordClickHandler() {
+        helper.getDistancesTable().addRecordClickHandler(new RecordClickHandler() {
             @Override
             public void onRecordClick(final RecordClickEvent e) {
                 final Record r = e.getRecord();
@@ -423,7 +388,7 @@
             }
         });
 
-        this.locationsTable.addRecordClickHandler(new RecordClickHandler() {
+        helper.getLocationsTable().addRecordClickHandler(new RecordClickHandler() {
             @Override
             public void onRecordClick(final RecordClickEvent e) {
                 final Record r = e.getRecord();
@@ -447,151 +412,11 @@
             }
         });
 
-        this.tabs = new TabSet();
-        this.tabs.setWidth100();
-        this.tabs.setHeight100();
-
-        final Tab locations = new Tab(this.MSG.locations());
-        final Tab distances = new Tab(this.MSG.distance());
-
-        locations.setPane(this.locationsTable);
-        distances.setPane(this.distancesTable);
-
-        this.tabs.addTab(locations, 0);
-        this.tabs.addTab(distances, 1);
-
-        this.filterResultCount = new StaticTextItem(this.MSG.resultCount());
-        this.filterResultCount.setTitleAlign(Alignment.LEFT);
-        this.filterResultCount.setTitleStyle("color: #000");
-
-        this.filterDescription = new TableFilter();
-        this.filterDescription.setHeight("30px");
-        this.filterDescription.addFilterHandler(this);
-
-        this.filterRange = new RangeTableFilter();
-        this.filterRange.setHeight("30px");
-        this.filterRange.addFilterHandler(this);
-        this.filterRange.setVisible(false);
-
-        final SelectItem filterCriteria = new SelectItem();
-        filterCriteria.setShowTitle(false);
-        filterCriteria.setWidth(100);
-        filterCriteria.addChangedHandler(new ChangedHandler() {
-            @Override
-            public void onChanged(final ChangedEvent e) {
-                if (e.getValue().toString().equals("range")) {
-                    DistancePanel.this.filterRange.setVisible(true);
-                    DistancePanel.this.filterDescription.setVisible(false);
-                    DistancePanel.this.filterDescription.clear();
-                } else {
-                    DistancePanel.this.filterRange.setVisible(false);
-                    DistancePanel.this.filterRange.clear();
-                    DistancePanel.this.filterDescription.setVisible(true);
-                }
-            }
-        });
-
-        final LinkedHashMap<String, String> filterMap = new LinkedHashMap<String, String>();
-        filterMap.put("description", this.MSG.description());
-        filterMap.put("range", this.MSG.range());
-        filterCriteria.setValueMap(filterMap);
-        filterCriteria.setValue("description");
-
-        final DynamicForm form = new DynamicForm();
-        form.setFields(filterCriteria);
-
-        final DynamicForm form2 = new DynamicForm();
-        form2.setFields(this.filterResultCount);
-
-        final HLayout filterLayout = new HLayout();
-        filterLayout.addMember(form);
-        filterLayout.addMember(this.filterDescription);
-        filterLayout.addMember(this.filterRange);
-        filterLayout.setHeight(30);
-        this.tabs.addTabSelectedHandler(new TabSelectedHandler() {
-            @Override
-            public void onTabSelected(final TabSelectedEvent evt) {
-                DistancePanel.this.filterDescription.clear();
-                DistancePanel.this.filterRange.clear();
-                DistancePanel.this.filterResultCount.setValue("");
-
-                final Canvas c = evt.getTabPane();
-                if (c instanceof ListGrid) {
-                    DistancePanel.this.currentFiltered = (ListGrid) c;
-                }
-            }
-        });
-
-        this.helperContainer.addMember(this.tabs);
-        this.helperContainer.addMember(filterLayout);
-        this.helperContainer.addMember(form2);
     }
 
     @Override
-    public void onFilterCriteriaChanged(final StringFilterEvent event) {
-        final String search = event.getFilter();
-
-        if (search != null && search.length() > 0) {
-            final Criteria c = new Criteria("description", search);
-            this.locationsTable.filterData(c);
-            this.distancesTable.filterData(c);
-            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
-        } else {
-            this.locationsTable.clearCriteria();
-            this.distancesTable.clearCriteria();
-            this.filterResultCount.setValue("");
-        }
-    }
-
-    @Override
-    public void onFilterCriteriaChanged(final RangeFilterEvent event) {
-        final Float from = event.getFrom() - 0.001f;
-        final Float to = event.getTo() + 0.001f;
-
-        Criterion combinedFilter = null;
-        Criterion locationFilter = null;
-
-        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
-            this.locationsTable.clearCriteria();
-            this.distancesTable.clearCriteria();
-            this.filterResultCount.setValue("");
-            return;
-        }
-
-        if (from.equals(Float.NaN)) {
-            combinedFilter = new Criterion("to", OperatorId.LESS_OR_EQUAL, to);
-
-            locationFilter = new Criterion("from", OperatorId.LESS_OR_EQUAL, to);
-
-            this.locationsTable.filterData(locationFilter);
-            this.distancesTable.filterData(combinedFilter);
-            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
-            return;
-        }
-
-        if (to.equals(Float.NaN)) {
-            combinedFilter = new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
-        } else {
-            final AdvancedCriteria c1 = new AdvancedCriteria(OperatorId.AND,
-                    new Criterion[] { new Criterion("from", OperatorId.GREATER_OR_EQUAL, from), new Criterion("from", OperatorId.LESS_OR_EQUAL, to) });
-
-            final AdvancedCriteria c2 = new AdvancedCriteria(OperatorId.AND,
-                    new Criterion[] { new Criterion("to", OperatorId.GREATER_OR_EQUAL, from), new Criterion("to", OperatorId.LESS_OR_EQUAL, to) });
-
-            final AdvancedCriteria c3 = new AdvancedCriteria(OperatorId.AND,
-                    new Criterion[] { new Criterion("from", OperatorId.LESS_OR_EQUAL, to), new Criterion("to", OperatorId.GREATER_OR_EQUAL, from) });
-
-            combinedFilter = new AdvancedCriteria(OperatorId.OR, new Criterion[] { c1, c2, c3 });
-        }
-        this.locationsTable.filterData(combinedFilter);
-        this.distancesTable.filterData(combinedFilter);
-        this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
-
-    }
-
-    protected String getRiverName() {
-        final ArtifactDescription adescr = this.artifact.getArtifactDescription();
-        return adescr.getRiver();
+    public void onBlur(final BlurEvent event) {
+        this.distancePanel.validateForm();
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanelInputHelper.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,229 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.client.client.ui;
+
+import java.util.LinkedHashMap;
+
+import org.dive4elements.river.client.client.Config;
+import org.dive4elements.river.client.client.FLYSConstants;
+import org.dive4elements.river.client.client.event.FilterHandler;
+import org.dive4elements.river.client.client.event.RangeFilterEvent;
+import org.dive4elements.river.client.client.event.StringFilterEvent;
+import org.dive4elements.river.client.client.ui.range.DistanceInfoDataSource;
+import org.dive4elements.river.client.client.ui.range.LocationsTable;
+import org.dive4elements.river.client.client.ui.range.RangeTable;
+
+import com.smartgwt.client.data.AdvancedCriteria;
+import com.smartgwt.client.data.Criteria;
+import com.smartgwt.client.data.Criterion;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.OperatorId;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.tab.Tab;
+import com.smartgwt.client.widgets.tab.TabSet;
+import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
+import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
+
+/** Panel to allow input of distance for calculation range. */
+public class DistancePanelInputHelper implements FilterHandler {
+
+    private RangeTable distancesTable;
+    private LocationsTable locationsTable;
+    private TabSet tabs;
+    private StaticTextItem filterResultCount;
+    private TableFilter filterDescription;
+    private RangeTableFilter filterRange;
+    private ListGrid currentFiltered;
+    protected final VLayout helperContainer;
+    private final FLYSConstants MSG;
+    private final String river;
+
+    public DistancePanelInputHelper(final FLYSConstants MSG, final VLayout helperContainer, final String river) {
+        this.MSG = MSG;
+        this.helperContainer = helperContainer;
+        this.river = river;
+
+        initHelperPanel(); // copy from DistancePanel
+    }
+
+    protected void initHelperPanel() {
+        this.distancesTable = new RangeTable();
+        this.locationsTable = new LocationsTable();
+
+        final Config config = Config.getInstance();
+        final String url = config.getServerUrl();
+        // final String river = getRiverName();
+
+        this.distancesTable.setAutoFetchData(true);
+        this.locationsTable.setAutoFetchData(true);
+        this.distancesTable.setDataSource(new DistanceInfoDataSource(url, this.river, "distances"));
+        this.locationsTable.setDataSource(new DistanceInfoDataSource(url, this.river, "locations"));
+
+        // recordClickHandlers were here
+
+        this.tabs = new TabSet();
+        this.tabs.setWidth100();
+        this.tabs.setHeight100();
+
+        final Tab locations = new Tab(this.MSG.locations());
+        final Tab distances = new Tab(this.MSG.distance());
+
+        locations.setPane(this.locationsTable);
+        distances.setPane(this.distancesTable);
+
+        this.tabs.addTab(locations, 0);
+        this.tabs.addTab(distances, 1);
+
+        this.filterResultCount = new StaticTextItem(this.MSG.resultCount());
+        this.filterResultCount.setTitleAlign(Alignment.LEFT);
+        this.filterResultCount.setTitleStyle("color: #000");
+
+        this.filterDescription = new TableFilter();
+        this.filterDescription.setHeight("30px");
+        this.filterDescription.addFilterHandler(this);
+
+        this.filterRange = new RangeTableFilter();
+        this.filterRange.setHeight("30px");
+        this.filterRange.addFilterHandler(this);
+        this.filterRange.setVisible(false);
+
+        final SelectItem filterCriteria = new SelectItem();
+        filterCriteria.setShowTitle(false);
+        filterCriteria.setWidth(100);
+        filterCriteria.addChangedHandler(new ChangedHandler() {
+            @Override
+            public void onChanged(final ChangedEvent e) {
+                if (e.getValue().toString().equals("range")) {
+                    DistancePanelInputHelper.this.filterRange.setVisible(true);
+                    DistancePanelInputHelper.this.filterDescription.setVisible(false);
+                    DistancePanelInputHelper.this.filterDescription.clear();
+                } else {
+                    DistancePanelInputHelper.this.filterRange.setVisible(false);
+                    DistancePanelInputHelper.this.filterRange.clear();
+                    DistancePanelInputHelper.this.filterDescription.setVisible(true);
+                }
+            }
+        });
+
+        final LinkedHashMap<String, String> filterMap = new LinkedHashMap<String, String>();
+        filterMap.put("description", this.MSG.description());
+        filterMap.put("range", this.MSG.range());
+        filterCriteria.setValueMap(filterMap);
+        filterCriteria.setValue("description");
+
+        final DynamicForm form = new DynamicForm();
+        form.setFields(filterCriteria);
+
+        final DynamicForm form2 = new DynamicForm();
+        form2.setFields(this.filterResultCount);
+
+        final HLayout filterLayout = new HLayout();
+        filterLayout.addMember(form);
+        filterLayout.addMember(this.filterDescription);
+        filterLayout.addMember(this.filterRange);
+        filterLayout.setHeight(30);
+        this.tabs.addTabSelectedHandler(new TabSelectedHandler() {
+            @Override
+            public void onTabSelected(final TabSelectedEvent evt) {
+                DistancePanelInputHelper.this.filterDescription.clear();
+                DistancePanelInputHelper.this.filterRange.clear();
+                DistancePanelInputHelper.this.filterResultCount.setValue("");
+
+                final Canvas c = evt.getTabPane();
+                if (c instanceof ListGrid) {
+                    DistancePanelInputHelper.this.currentFiltered = (ListGrid) c;
+                }
+            }
+        });
+
+        this.helperContainer.addMember(this.tabs);
+        this.helperContainer.addMember(filterLayout);
+        this.helperContainer.addMember(form2);
+    }
+
+    @Override
+    public void onFilterCriteriaChanged(final StringFilterEvent event) {
+        final String search = event.getFilter();
+
+        if (search != null && search.length() > 0) {
+            final Criteria c = new Criteria("description", search);
+            this.locationsTable.filterData(c);
+            this.distancesTable.filterData(c);
+            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
+        } else {
+            this.locationsTable.clearCriteria();
+            this.distancesTable.clearCriteria();
+            this.filterResultCount.setValue("");
+        }
+    }
+
+    @Override
+    public void onFilterCriteriaChanged(final RangeFilterEvent event) {
+        final Float from = event.getFrom() - 0.001f;
+        final Float to = event.getTo() + 0.001f;
+
+        Criterion combinedFilter = null;
+        Criterion locationFilter = null;
+
+        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
+            this.locationsTable.clearCriteria();
+            this.distancesTable.clearCriteria();
+            this.filterResultCount.setValue("");
+            return;
+        }
+
+        if (from.equals(Float.NaN)) {
+            combinedFilter = new Criterion("to", OperatorId.LESS_OR_EQUAL, to);
+
+            locationFilter = new Criterion("from", OperatorId.LESS_OR_EQUAL, to);
+
+            this.locationsTable.filterData(locationFilter);
+            this.distancesTable.filterData(combinedFilter);
+            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
+            return;
+        }
+
+        if (to.equals(Float.NaN)) {
+            combinedFilter = new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
+        } else {
+            final AdvancedCriteria c1 = new AdvancedCriteria(OperatorId.AND,
+                    new Criterion[] { new Criterion("from", OperatorId.GREATER_OR_EQUAL, from), new Criterion("from", OperatorId.LESS_OR_EQUAL, to) });
+
+            final AdvancedCriteria c2 = new AdvancedCriteria(OperatorId.AND,
+                    new Criterion[] { new Criterion("to", OperatorId.GREATER_OR_EQUAL, from), new Criterion("to", OperatorId.LESS_OR_EQUAL, to) });
+
+            final AdvancedCriteria c3 = new AdvancedCriteria(OperatorId.AND,
+                    new Criterion[] { new Criterion("from", OperatorId.LESS_OR_EQUAL, to), new Criterion("to", OperatorId.GREATER_OR_EQUAL, from) });
+
+            combinedFilter = new AdvancedCriteria(OperatorId.OR, new Criterion[] { c1, c2, c3 });
+        }
+        this.locationsTable.filterData(combinedFilter);
+        this.distancesTable.filterData(combinedFilter);
+        this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
+
+    }
+
+    public ListGrid getDistancesTable() {
+        return this.distancesTable;
+    }
+
+    public ListGrid getLocationsTable() {
+        return this.locationsTable;
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/PanelHelper.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/PanelHelper.java	Fri Jul 13 11:40:25 2018 +0200
@@ -9,10 +9,18 @@
  */
 package org.dive4elements.river.client.client.ui;
 
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.ListGridFieldType;
 import com.smartgwt.client.widgets.form.fields.IntegerItem;
 import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator;
 import com.smartgwt.client.widgets.form.validator.IsIntegerValidator;
 import com.smartgwt.client.widgets.form.validator.Validator;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.SortNormalizer;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
 import com.smartgwt.client.widgets.layout.VLayout;
 
 /**
@@ -63,4 +71,48 @@
         return inputItem;
 
     }
+
+    public static final ListGridField createRemoveField(final ListGrid table, final String icon) {
+        final ListGridField removeField = new ListGridField("_removeRecord", "Remove Record") {
+            {
+                setType(ListGridFieldType.ICON);
+                setIcon(icon);
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+                setCanDragResize(false);
+                super.setCanToggle(false);
+            }
+        };
+        table.addRecordClickHandler(new RecordClickHandler() {
+            @Override
+            public void onRecordClick(final RecordClickEvent event) {
+                // Just handle remove-clicks
+                if (!event.getField().getName().equals(removeField.getName())) {
+                    return;
+                }
+                event.getViewer().removeData(event.getRecord());
+            }
+        });
+
+        return removeField;
+    }
+
+    public static final ListGridField createIntTableField(final String key, final String msg, final boolean canSort, final SortNormalizer normalizer,
+            final IntegerRangeValidator validators) {
+        final ListGridField intField = new ListGridField(key, msg);
+        intField.setType(ListGridFieldType.INTEGER);
+        intField.setValidators(validators);
+        intField.setWidth(90);
+        intField.setAlign(Alignment.RIGHT);
+        intField.setSortNormalizer(normalizer);
+        intField.setCanSort(canSort);
+        intField.setCanDragResize(false);
+
+        return intField;
+    }
+
 }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Fri Jul 13 11:40:25 2018 +0200
@@ -30,8 +30,9 @@
 import org.dive4elements.river.client.client.ui.sinfo.FlowDepthTwinPanel;
 import org.dive4elements.river.client.client.ui.sq.SQPeriodPanel;
 import org.dive4elements.river.client.client.ui.uinfo.LoadSedimentHeightPanel;
-import org.dive4elements.river.client.client.ui.uinfo.LoadSingleEpochSelect;
 import org.dive4elements.river.client.client.ui.uinfo.LoadSingleYearPanel;
+import org.dive4elements.river.client.client.ui.uinfo.LoadSingleYearPseudoEpochPanel;
+import org.dive4elements.river.client.client.ui.uinfo.SupraRegionalTablePanel;
 import org.dive4elements.river.client.client.ui.uinfo.VegetationzonesTableEditPanel;
 import org.dive4elements.river.client.client.ui.uinfo.VegetationzonesTablePanel;
 import org.dive4elements.river.client.shared.model.User;
@@ -71,6 +72,8 @@
             return new DistanceOnlyPanel();
         } else if (uiProvider.equals("distance_only_part_panel")) {
             return new DistanceOnlyPartPanel();
+        } else if (uiProvider.equals("distance_only_part_historical_panel")) {
+            return new DistanceOnlyPartHistoricalPanel();
         } else if (uiProvider.equals("waterlevel_ground_panel")) {
             return new WaterlevelGroundPanel();
         } else if (uiProvider.equals("wq_panel")) {
@@ -165,8 +168,10 @@
             return new CollisionLoadEpochPanel();
         } else if (uiProvider.equals("common.state.load_single_year_select")) {
             return new LoadSingleYearPanel();
-        } else if (uiProvider.equals("common.load_single_epoch_select")) {
-            return new LoadSingleEpochSelect();
+        } else if (uiProvider.equals("common.state.load_single_year_select.show_hint")) {
+            return new LoadSingleYearPanel(true);
+        } else if (uiProvider.equals("uinfo.salix.load_single_year_pseudo_epoch_select")) {
+            return new LoadSingleYearPseudoEpochPanel();
         } else if (uiProvider.equals("minfo.sedimentload_sqti_select")) {
             return new SedLoadSQTiPanel();
         } else if (uiProvider.equals("uinfo.sedimentheight_select")) {
@@ -179,6 +184,8 @@
             return new UserRGDProvider();
         } else if (uiProvider.equals("static_sqrelation")) {
             return new StaticDataPanel();
+        } else if (uiProvider.equals("uinfo.salix.supraregional.table")) {
+            return new SupraRegionalTablePanel();
         }
 
         if ("sinfo_flowdepth_twin_panel".equals(uiProvider))
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelGroundPanel.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelGroundPanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -121,7 +121,7 @@
     }
 
     @Override
-    protected void initHelperPanel() {
+    protected void initHelperPanel(final DataList data) {
         // We don't need a helper panel here. But we have to override this
         // method to avoid the table creation in the parent class.
     }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/LoadSingleEpochSelect.java	Fri Jul 06 13:18:51 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * 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.client.client.ui.uinfo;
-
-import org.dive4elements.river.client.client.ui.AbstractEpochPanel;
-import org.dive4elements.river.client.client.ui.PanelHelper;
-import org.dive4elements.river.client.shared.model.DataList;
-
-import com.smartgwt.client.widgets.Canvas;
-import com.smartgwt.client.widgets.Label;
-import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.TextItem;
-import com.smartgwt.client.widgets.layout.VLayout;
-
-public class LoadSingleEpochSelect extends AbstractEpochPanel {
-
-    private static final long serialVersionUID = 1L;
-
-    public LoadSingleEpochSelect() {
-        super(Type.single);
-    }
-
-    @Override
-    protected String getDatakey() {
-        return "singleepoch";
-    }
-
-    @Override
-    protected Canvas createWidget(final DataList data) {
-        final VLayout root = new VLayout();
-
-        final Label title = new Label(data.get(0).getDescription());
-        title.setHeight("25px");
-
-        final DynamicForm form = new DynamicForm();
-        form.setNumCols(4);
-        final TextItem start = createStartInputItem(this.MSG.from());
-        start.setCanEdit(false);
-
-        final TextItem end = createEndInputItem(this.MSG.to());
-        end.setCanEdit(false);
-
-        form.setFields(start, end);
-
-        root.addMember(title);
-        root.addMember(PanelHelper.getSpacer(10));
-        root.addMember(form);
-
-        return root;
-    }
-
-}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/LoadSingleYearPanel.java	Fri Jul 06 13:18:51 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/LoadSingleYearPanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -19,10 +19,18 @@
 
 public class LoadSingleYearPanel extends AbstractSingleItemPanel {
 
+    private static final long serialVersionUID = 1L;
+    private boolean showHint = false;
+
     public LoadSingleYearPanel() {
         super(Type.single);
     }
 
+    public LoadSingleYearPanel(final boolean showHint) {
+        super(Type.single);
+        this.showHint = showHint;
+    }
+
     @Override
     protected String getDatakey() {
         return "singleyear";
@@ -44,6 +52,9 @@
         form.setNumCols(4);
 
         final TextItem inputItem = createInputItem("YEAR_INPUT");
+        inputItem.setShowHint(this.showHint);
+        inputItem.setHint(this.MSG.common_input_hint_year());
+        inputItem.setShowHintInField(true);
         inputItem.setShowTitle(false);
         form.setFields(inputItem);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/LoadSingleYearPseudoEpochPanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.client.client.ui.uinfo;
+
+public class LoadSingleYearPseudoEpochPanel extends LoadSingleYearPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected String getDatakey() {
+        return "singleepoch";
+    }
+
+    @Override
+    protected String errorForItemMsg() {
+        return this.MSG.no_data_for_year();// NO DATA FOR EPOCH TODO möglicherweise, wenn der ablauf klar ist
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/uinfo/SupraRegionalTablePanel.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,423 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.client.client.ui.uinfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dive4elements.river.client.client.ui.AbstractUIProvider;
+import org.dive4elements.river.client.client.ui.DistancePanelInputHelper;
+import org.dive4elements.river.client.client.ui.PanelHelper;
+import org.dive4elements.river.client.shared.model.Data;
+import org.dive4elements.river.client.shared.model.DataItem;
+import org.dive4elements.river.client.shared.model.DataList;
+import org.dive4elements.river.client.shared.model.DefaultData;
+import org.dive4elements.river.client.shared.model.DefaultDataItem;
+import org.dive4elements.river.client.shared.model.SalixZone;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.user.client.ui.Label;
+import com.smartgwt.client.data.Record;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.grid.CellEditValueFormatter;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.CellSavedEvent;
+import com.smartgwt.client.widgets.grid.events.CellSavedHandler;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.Layout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+public class SupraRegionalTablePanel extends AbstractUIProvider {
+    private static final long serialVersionUID = 1L;
+
+    private Double minKm, maxKm = -1.;
+    // private String tableData = "";
+    private ListGrid table;
+    private final String datakey = "supraregional_table";
+    final Label validationLabel = new Label();
+
+    private final NumberFormat format = NumberFormat.getDecimalFormat();
+
+    @Override
+    public Canvas createOld(final DataList dataList) {
+        final HLayout layout = new HLayout();
+        layout.setWidth("400px");
+        final VLayout vLayout = new VLayout();
+        vLayout.setWidth(130);
+        final Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+        label.setHeight("25px");
+
+        final List<Data> items = dataList.getAll();
+        final Data str = getData(items, this.datakey);
+        final DataItem[] strItems = str.getItems();
+
+        final List<SalixZone> entries = SalixZone.parse(strItems[0].getLabel());
+
+        for (final SalixZone entry : entries) {
+            final Label dateLabel = new Label(
+                    entry.getDwsplValue() + " (" + this.format.format(entry.getFromKm()) + "-" + this.format.format(entry.getToKm()) + " km)");
+            dateLabel.setHeight("20px");
+            vLayout.addMember(dateLabel);
+        }
+        final Canvas back = getBackButton(dataList.getState());
+        layout.addMember(label);
+        layout.addMember(vLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+    @Override
+    public Canvas create(final DataList data) {
+
+        final Data dataItem = data.getAll().get(0);
+        String tableData = "";
+        for (final DataItem item : dataItem.getItems()) {
+            final String label = item.getLabel();
+            if (label.equals("salix_zones_min"))
+                this.minKm = Double.valueOf(item.getStringValue());
+            else if (label.equals("salix_zones_max"))
+                this.maxKm = Double.valueOf(item.getStringValue());
+            else if (label.equals("salix_zones"))
+                tableData = item.getStringValue();
+        }
+
+        if (this.minKm > this.maxKm) {
+            final double temp = this.minKm;
+            this.minKm = this.maxKm;
+            this.maxKm = temp;
+        }
+
+        final VLayout layout = new VLayout();
+        final Canvas submit = getNextButton();
+
+        final VLayout root = new VLayout();
+        root.setWidth(420);
+        createWidget(root, data, tableData);
+
+        layout.addMember(root);
+        layout.addMember(submit);
+
+        validateRangeOverlap();// init Text
+        return layout;
+    }
+
+    @Override
+    protected Data[] getData() {
+        final List<Data> data = new ArrayList<Data>();
+
+        final ListGridRecord[] lgr = this.table.getRecords();
+        if (lgr == null) {
+            return new Data[0];
+        }
+        final List<SalixZone> zoneList = getSalixZones(lgr);
+        final DataItem item = new DefaultDataItem(this.datakey, null, SalixZone.parseListToDataString(zoneList));
+        data.add(new DefaultData(this.datakey, null, null, new DataItem[] { item }));
+        return data.toArray(new Data[data.size()]);
+    }
+
+    private List<SalixZone> getSalixZones(final ListGridRecord[] lgr) {
+        final List<SalixZone> zoneList = new ArrayList<SalixZone>();
+        for (final ListGridRecord element : lgr) {
+            final Record r = element;
+            final SalixZone zone = SalixZone.createFromTableEntry(r.getAttribute("dmwspl"), r.getAttribute("from"), r.getAttribute("to"));
+            zoneList.add(zone);
+        }
+        return zoneList;
+    }
+
+    public Canvas createWidget(final Layout root, final DataList data, final String tableData) {
+
+        this.table = createTable(root, data, tableData);
+        final TextItem dwspl = PanelHelper.createItem("_label_dwspl", this.MSG.uinfo_salix_dmwspl_short(), "50");
+        final TextItem start = PanelHelper.createIntegerItem("_from_dwspl", getLabelFromTo(this.MSG.from()), "50");
+        final TextItem end = PanelHelper.createIntegerItem("_to_dwspl", getLabelFromTo(this.MSG.to()), "50");
+
+        final HLayout fields = new HLayout();
+
+        final Button add = new Button(this.MSG.add_date()); // TODO: make key more generic or change to more specific
+
+        final DynamicForm newEntryForm = new DynamicForm();
+        newEntryForm.setWidth(320);
+        newEntryForm.setNumCols(12);
+        newEntryForm.setFields(start, end, dwspl);
+
+        add.addClickHandler(new ClickHandler() {
+            @Override
+            public void onClick(final ClickEvent ce) {
+                final String v1 = start.getValueAsString();
+                final String v2 = end.getValueAsString();
+                final String v3 = dwspl.getValueAsString();
+                final String message = validate(v1, v2, v3);
+                if (message != null) {
+                    SC.warn(message);
+                    return;
+                }
+                final ListGridRecord r = new ListGridRecord();
+                r.setAttribute("dmwspl", v3);
+                r.setAttribute("from", SupraRegionalTablePanel.this.format.parse(v1));
+                r.setAttribute("to", SupraRegionalTablePanel.this.format.parse(v2));
+                SupraRegionalTablePanel.this.table.addData(r);
+                validateRangeOverlap();
+            }
+        });
+
+        fields.addMember(newEntryForm);
+
+        root.addMember(fields);
+        root.addMember(PanelHelper.getSpacer(10));
+
+        initHelperPanel(start, end);
+
+        root.addMember(add);
+        root.addMember(PanelHelper.getSpacer(20));
+        return root;
+    }
+
+    private String getLabelFromTo(final String fromOrTo) {
+        return new StringBuilder().append(fromOrTo).append(" [").append(this.MSG.dpUnitFrom()).append("]").toString();
+    }
+
+    protected void initHelperPanel(final TextItem start, final TextItem end) {
+        final DistancePanelInputHelper helper = new DistancePanelInputHelper(this.MSG, this.helperContainer, this.getRiverName());
+
+        helper.getDistancesTable().addRecordClickHandler(new RecordClickHandler() {
+            @Override
+            public void onRecordClick(final RecordClickEvent e) {
+                final Record r = e.getRecord();
+
+                final String from = r.getAttribute("from");
+                final String to = r.getAttribute("to");
+
+                try {
+                    start.setValue(SupraRegionalTablePanel.this.format.format(Double.valueOf(from)));
+                    end.setValue(SupraRegionalTablePanel.this.format.format(Double.valueOf(to)));
+                }
+                catch (final NumberFormatException nfe) {
+                    SC.warn(SupraRegionalTablePanel.this.MSG.wrongFormat());
+                }
+            }
+        });
+
+        helper.getLocationsTable().addRecordClickHandler(new RecordClickHandler() {
+            @Override
+            public void onRecordClick(final RecordClickEvent e) {
+                final Record r = e.getRecord();
+                final int field = e.getFieldNum();
+
+                try {
+                    final String value = r.getAttribute("from");
+                    switch (field) {
+                    case 0:
+                        start.setValue(SupraRegionalTablePanel.this.format.format(Double.valueOf(value)));
+                        break;
+                    case 1:
+                        end.setValue(SupraRegionalTablePanel.this.format.format(Double.valueOf(value)));
+                        break;
+                    }
+                }
+                catch (final NumberFormatException nfe) {
+                    SC.warn(SupraRegionalTablePanel.this.MSG.wrongFormat());
+                }
+            }
+        });
+
+    }
+
+    protected final ListGrid createTable(final Layout root, final DataList data, final String tableData) {
+
+        final Label title = new Label(data.get(0).getDescription());
+        title.setHeight("35px");
+        this.validationLabel.setHeight("10px");
+        this.validationLabel.getElement().getStyle().setColor("red");
+        final ListGrid elements = new ListGrid();
+        elements.setWidth(320);
+        elements.setHeight(300);
+        elements.setShowHeaderContextMenu(false);
+        elements.setCanReorderFields(false);
+        elements.setCanResizeFields(false);
+        elements.setCanEdit(true);
+        elements.setCanSort(false);
+        elements.setCanResizeFields(false);
+
+        final ListGridField dmwsplField = new ListGridField("dmwspl", this.MSG.uinfo_salix_dmwspl_short());
+        dmwsplField.setAlign(Alignment.RIGHT);
+        dmwsplField.setWidth(95);
+        dmwsplField.addCellSavedHandler(new CellSavedHandler() {
+            @Override
+            public void onCellSaved(final CellSavedEvent event) {
+                final Object value = event.getNewValue();
+                event.getRecord().setAttribute("dmwspl", event.getOldValue());
+                try {
+                    final int intValue = Integer.valueOf(String.valueOf(value));
+                    event.getRecord().setAttribute("dmwspl", intValue);
+                }
+                catch (final NumberFormatException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+        final ListGridField fromField = createDoubleTableField("from", getLabelFromTo(this.MSG.from()));
+        final ListGridField toField = createDoubleTableField("to", getLabelFromTo(this.MSG.to()));
+        final ListGridField removeField = PanelHelper.createRemoveField(elements, GWT.getHostPageBaseURL() + this.MSG.removeFeature());
+        elements.addRecordClickHandler(new RecordClickHandler() { // adding another custom record-Remove-Handler which is not included in the Panelhelper
+            @Override
+            public void onRecordClick(final RecordClickEvent event) {
+                if (event.getField().getName().equals(removeField.getName())) {
+                    validateRangeOverlap();
+                }
+            }
+        });
+        elements.setFields(fromField, toField, dmwsplField, removeField);
+        addDataInit(elements, tableData);
+
+        root.addMember(title);
+        root.addMember(elements);
+        root.addMember(PanelHelper.getSpacer(3));
+        root.addMember(this.validationLabel);
+        root.addMember(PanelHelper.getSpacer(4));
+        return elements;
+    }
+
+    private void addDataInit(final ListGrid table, final String tableData) {
+        if (tableData != null) {
+            final List<SalixZone> rows = SalixZone.parse(tableData);
+            for (final SalixZone row : rows) {
+                table.addData(createEntry(row));
+            }
+        }
+    }
+
+    public final ListGridRecord createEntry(final SalixZone row) {
+
+        final Integer dwspl = row.getDwsplValue();
+        final Double from = row.getFromKm();
+        final Double to = row.getToKm();
+
+        if (dwspl == null || from == null || to == null) {
+            return null;
+        }
+
+        final ListGridRecord r = new ListGridRecord();
+        r.setAttribute("dmwspl", dwspl);
+        r.setAttribute("from", from);
+        r.setAttribute("to", to);
+
+        return r;
+
+    }
+
+    private ListGridField createDoubleTableField(final String key, final String msg) {
+        final ListGridField field = new ListGridField(key, msg);
+        field.setAlign(Alignment.RIGHT);
+        field.setWidth(90);
+        field.addCellSavedHandler(new CellSavedHandler() {
+            @Override
+            public void onCellSaved(final CellSavedEvent event) {
+                final Object value = event.getNewValue();
+                event.getRecord().setAttribute(key, event.getOldValue());
+                try {
+                    final double d = SupraRegionalTablePanel.this.format.parse(String.valueOf(value));
+                    if (d > SupraRegionalTablePanel.this.maxKm) {
+                        event.getRecord().setAttribute(key, SupraRegionalTablePanel.this.maxKm);
+                    } else if (d < SupraRegionalTablePanel.this.minKm) {
+                        event.getRecord().setAttribute(key, SupraRegionalTablePanel.this.minKm);
+                    } else {
+                        event.getRecord().setAttribute(key, d);
+                    }
+                    validateRangeOverlap();
+                }
+                catch (final NumberFormatException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        field.setEditValueFormatter(new CellEditValueFormatter() {
+            @Override
+            public Object format(final Object value, final ListGridRecord record, final int rowNum, final int colNum) {
+                if (!(value instanceof Float || value instanceof Double)) {
+                    try {
+                        return (float) SupraRegionalTablePanel.this.format.parse(String.valueOf(value));
+                    }
+                    catch (final Exception e2) {
+                        return record.getAttribute(key);
+                    }
+                } else {
+                    return SupraRegionalTablePanel.this.format.format((Double) value);
+                }
+            }
+        });
+        field.setCellFormatter(new CellFormatter() {
+            @Override
+            public String format(final Object value, final ListGridRecord record, final int rowNum, final int colNum) {
+                return SupraRegionalTablePanel.this.format.format(Double.valueOf(String.valueOf(value)));
+            }
+        });
+        return field;
+    }
+
+    private String validate(final String fromInput, final String toInput, final String dmwspl) {
+
+        final List<SalixZone> zones = getSalixZones(this.table.getRecords());
+
+        if (fromInput == null || toInput == null || dmwspl == null || fromInput.trim().isEmpty() || toInput.trim().isEmpty() || dmwspl.trim().isEmpty())
+            return this.MSG.uinfo_vegetation_zones_validation_empty();
+
+        try {
+            final Double from = this.format.parse(fromInput);
+            final Double to = this.format.parse(toInput);
+            Integer.valueOf(dmwspl);
+
+            if (!SalixZone.hasGaps(zones, this.minKm, this.maxKm))
+                return this.MSG.uinfo_salix_input_complete();
+
+            if (from < this.minKm || from > this.maxKm || to > this.maxKm || to < this.minKm)
+                return this.MSG.uinfo_salix_km_limit_exceed();
+
+            // range anschluss
+            if (!SalixZone.isValidAnschlussRange(from, to, zones, this.minKm)) {
+                return this.MSG.uinfo_salix_km_anschluss();
+            }
+            return null;
+        }
+        catch (final NumberFormatException e) {
+            return this.MSG.wrongFormat();
+        }
+    }
+
+    @Override
+    public List<String> validate() {
+        final List<String> errors = new ArrayList<String>();
+
+        if (SalixZone.zonesAreOverlapping(this.getSalixZones(this.table.getRecords())))
+            errors.add(this.MSG.uinfo_salix_km_overlap());
+        if (SalixZone.hasGaps(this.getSalixZones(this.table.getRecords()), this.minKm, this.maxKm))
+            errors.add(this.MSG.uinfo_salix_km_has_gaps());// "Der Km-Bereich wird nicht vollst. abgedeckt.";
+        return errors;
+    }
+
+    private void validateRangeOverlap() {
+        this.validationLabel.setText(validate().toString().replace("[", "").replace("]", "").replace(",", ""));
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/SalixZone.java	Fri Jul 13 11:40:25 2018 +0200
@@ -0,0 +1,177 @@
+/** 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.client.shared.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class SalixZone implements Comparable<SalixZone> {
+
+    // IMMER ABGLEICHEN Server Client SalixZone.java
+    private static final String TABLE_CELL_SEPARATOR = "TABLE_CELL_SEPARATOR";
+    private static final String TABLE_ROW_SEPARATOR = "TABLE_ROW_SEPARATOR";
+    private final int dwsplValue;
+    private final double fromKm;
+    private final double toKm;
+
+    private final static double DELTA = 0.0001;
+
+    public static List<SalixZone> parse(final String zonesRaw) {
+        final List<SalixZone> resultList = new ArrayList<SalixZone>();
+
+        final List<String[]> results = new ArrayList<String[]>();
+        if (zonesRaw.contains(TABLE_ROW_SEPARATOR)) {
+            final String[] rows = zonesRaw.split(TABLE_ROW_SEPARATOR);
+            for (final String row : rows) {
+                if (row.contains(TABLE_CELL_SEPARATOR)) {
+                    final String[] result = row.split(TABLE_CELL_SEPARATOR);
+                    results.add(result);
+                }
+            }
+        }
+        for (final String[] zone : results) {
+            final SalixZone helper = new SalixZone(Integer.valueOf(zone[0]), Double.valueOf(zone[1]), Double.valueOf(zone[2]));
+            resultList.add(helper);
+        }
+        return resultList;
+    }
+
+    public static SalixZone createFromTableEntry(final String dwspl, final String from, final String to) {
+        return new SalixZone(Integer.valueOf(dwspl), Double.valueOf(from), Double.valueOf(to)); // Error-Handling?
+    }
+
+    private SalixZone(final int dwsplValue, final double fromKm, final double toKm) {
+        this.dwsplValue = dwsplValue;
+        this.fromKm = fromKm;
+        this.toKm = toKm;
+    }
+
+    public Double getToKm() {
+        return this.toKm;
+    }
+
+    public int getDwsplValue() {
+        return this.dwsplValue;
+    }
+
+    public Double getFromKm() {
+        return this.fromKm;
+    }
+
+    public static final String parseListToDataString(final List<SalixZone> list) {
+
+        java.util.Collections.sort(list);
+        final StringBuilder builder = new StringBuilder();
+        for (final SalixZone zone : list) {
+            builder.append(zone.getDwsplValue());
+            builder.append(TABLE_CELL_SEPARATOR);
+            builder.append(zone.getFromKm());
+            builder.append(TABLE_CELL_SEPARATOR);
+            builder.append(zone.getToKm());
+            builder.append(TABLE_ROW_SEPARATOR);
+        }
+        return builder.toString();
+    }
+
+    public static final boolean zonesAreOverlapping(final List<SalixZone> list) {
+        for (final SalixZone zone : list) {
+            for (final SalixZone zoneOther : list) {
+                if (zone != zoneOther) {
+                    final boolean overlaps = zone.overlaps(zoneOther);
+                    if (overlaps) {
+                        return overlaps; // cancel. only one zone has to overlap
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public static final boolean hasGaps(final List<SalixZone> list, final double lower, final double upper) {
+
+        if (((upper - lower) > DELTA) && list.size() == 0)
+            return true;
+
+        final TreeSet<SalixZone> treeList = new TreeSet<SalixZone>();
+        treeList.addAll(list);
+        double lowerCompare = lower + DELTA;
+        for (final SalixZone zone : treeList) {
+            if ((zone.getUpperFromTo() - zone.getLowerFromTo()) > DELTA) {
+                if (zone.getLowerFromTo() > lowerCompare) {
+                    return true;
+                }
+                lowerCompare = zone.getUpperFromTo() + DELTA;
+            }
+        }
+        if ((lowerCompare + DELTA) < upper)
+            return true; // am Ende nicht geschlossen
+
+        return false;
+    }
+
+    public Double getLowerFromTo() {
+        return this.fromKm < this.toKm ? this.fromKm : this.toKm; // Math. is forbidden :-(
+    }
+
+    public Double getUpperFromTo() {
+        return this.fromKm > this.toKm ? this.fromKm : this.toKm;// Math. is forbidden :-(
+    }
+
+    private boolean overlaps(final SalixZone otherZone) {
+        final double otherLower = otherZone.getLowerFromTo();
+        final double otherUpper = otherZone.getUpperFromTo();
+
+        final double upper = getUpperFromTo();
+        final double lower = getLowerFromTo();
+        final double otherSchwerpunkt = (otherLower + otherUpper) / 2;
+        if ((otherUpper < upper && otherUpper > lower)) {
+            return true;
+        } else if (otherLower > lower && otherLower < upper) {
+            return true;
+        } else if (otherSchwerpunkt > (lower - DELTA) && otherSchwerpunkt < (upper + DELTA)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int compareTo(final SalixZone o) {
+        final int basicCompare = this.getLowerFromTo().compareTo(o.getLowerFromTo());
+        if (basicCompare == 0) {
+            return 1; // necessary for the treeSet!
+        }
+        return basicCompare;
+    }
+
+    public static boolean isValidAnschlussRange(final double fromTest, final double toTest, final List<SalixZone> list, final double minKm) {
+        final SalixZone zone = new SalixZone(0, fromTest, toTest);
+        final double lower = zone.getLowerFromTo();
+        final double anschluss = getAnschluss(list, minKm);
+        final double differenceAbs = (lower - anschluss) > 0 ? (lower - anschluss) : (anschluss - lower); // no Math.abs allowed :-(
+        if (differenceAbs > DELTA) {
+            return false;
+        }
+        return true;
+    }
+
+    private static double getAnschluss(final List<SalixZone> list, final double minKm) {
+        if (list.size() > 0) {
+            return list.get(list.size() - 1).getUpperFromTo();
+        }
+        return minKm;
+    }
+}

http://dive4elements.wald.intevation.org