changeset 9404:bc9a45d2b1fa

common time range for gauges incl. error messages
author gernotbelger
date Wed, 15 Aug 2018 13:59:09 +0200
parents e2da9c8a7c57
children 34cd4faf43f4
files artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractDynamicMainValuesService.java artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesService.java artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties backend/src/main/java/org/dive4elements/river/model/Gauge.java backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesService.java gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesServiceAsync.java gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesTimeRangeDeterminationService.java gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesTimeRangeDeterminationServiceAsync.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DoubleArrayPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesServiceImpl.java gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesTimeRangeDeterminationServiceImpl.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DischargeInfoObjectImpl.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/GaugeInfoObject.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/GaugeInfoObjectImpl.java gwt-client/src/main/webapp/WEB-INF/features.xml gwt-client/src/main/webapp/WEB-INF/web.xml
diffstat 26 files changed, 1056 insertions(+), 332 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractDynamicMainValuesService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,96 @@
+/* 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.services;
+
+import java.util.Date;
+import java.util.List;
+
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.GlobalContext;
+import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+import org.dive4elements.river.model.Gauge;
+import org.dive4elements.river.model.MainValue;
+import org.dive4elements.river.model.River;
+import org.w3c.dom.Document;
+
+/**
+ * This service returns the main values of a river's gauge based on the start
+ * and end point of the river.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+abstract public class AbstractDynamicMainValuesService extends AbstractMainValuesService {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) {
+        try {
+
+            final River river = getRequestedRiver(data, "/art:mainvalues/art:river/text()");
+            final Gauge gauge = getRequestedGauge(data, river);
+            final Date startTime = getRequestedStartDate(data, "/art:mainvalues/art:startDate/text()");
+            final Date endTime = getRequestedEndDate(data, "/art:mainvalues/art:endDate/text()");
+
+            final List<MainValue> mainValues = getMainValues(river, gauge, startTime, endTime);
+
+            return buildDocument(river, gauge, mainValues, context);
+        }
+        catch (final MainValuesServiceException e) {
+            // e.printStackTrace();
+            return error(e.getMessage());
+        }
+        catch (final Exception e) {
+            e.printStackTrace();
+            return error(e.getMessage());
+        }
+    }
+
+    public static final Date getRequestedStartDate(final Document data, final String XPATH_END_YEAR) throws MainValuesServiceException {
+
+        final String startStr = XMLUtils.xpathString(data, XPATH_END_YEAR, ArtifactNamespaceContext.INSTANCE);
+
+        if (startStr == null)
+            throw new MainValuesServiceException("no start date");
+
+        try {
+            return new Date(Long.parseLong(startStr));
+            // FIXME: timezone? probably must match timezone of database
+        }
+        catch (final NumberFormatException e) {
+            e.printStackTrace();
+            throw new MainValuesServiceException("invalid start date");
+        }
+    }
+
+    public static final Date getRequestedEndDate(final Document data, final String XPATH_END_DATE) throws MainValuesServiceException {
+
+        final String endStr = XMLUtils.xpathString(data, XPATH_END_DATE, ArtifactNamespaceContext.INSTANCE);
+
+        if (endStr == null)
+            throw new MainValuesServiceException("no end date");
+
+        try {
+            return new Date(Long.parseLong(endStr));
+            // FIXME: timezone? probably must match timezone of database
+        }
+        catch (final NumberFormatException e) {
+            e.printStackTrace();
+            throw new MainValuesServiceException("invalid end date");
+        }
+    }
+
+    /**
+     * Computes a gauge's main values for a period of time based on its daily discharges stored in the database
+     */
+    protected abstract List<MainValue> getMainValues(final River river, final Gauge gauge, final Date startTime, final Date endTime)
+            throws MainValuesServiceException;
+
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -47,7 +47,6 @@
     private static Logger log = Logger.getLogger(AbstractMainValuesService.class);
 
     /** XPath that points to the river definition of the incoming request. */
-    private static final String XPATH_RIVER = "/art:mainvalues/art:river/text()";
 
     /** XPath that points to the start definition of the incoming request. */
     private static final String XPATH_START = "/art:mainvalues/art:start/text()";
@@ -70,7 +69,7 @@
      *
      * @return the River object.
      */
-    protected final River getRequestedRiver(final Document data) throws MainValuesServiceException {
+    protected static final River getRequestedRiver(final Document data, final String XPATH_RIVER) throws MainValuesServiceException {
         log.debug("MainValuesService.getRequestedRiver");
 
         String riverStr = XMLUtils.xpathString(data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE);
@@ -81,7 +80,7 @@
         throw new MainValuesServiceException("no river found.");
     }
 
-    protected final Gauge getRequestedGauge(final Document data, final River river) throws MainValuesServiceException {
+    protected static final Gauge getRequestedGauge(final Document data, final River river) throws MainValuesServiceException {
 
         final double[] minmax = getRequestedStartEnd(data, river);
         final Gauge gauge = river.determineRefGauge(minmax, CMP.compare(minmax[0], minmax[1]) != 0);
@@ -105,7 +104,7 @@
      *
      * @return the start and end point.
      */
-    private double[] getRequestedStartEnd(final Document data, final River river) {
+    public static double[] getRequestedStartEnd(final Document data, final River river) {
         log.debug("MainValuesService.getStartEnd");
 
         final String startStr = XMLUtils.xpathString(data, XPATH_START, ArtifactNamespaceContext.INSTANCE);
@@ -165,7 +164,7 @@
      * @param context
      *            The context object.
      */
-    private void appendMetaInformation(final Document doc, final Element root, final River river, final Gauge gauge, final Object context) {
+    static void appendMetaInformation(final Document doc, final Element root, final River river, final Gauge gauge, final Object context) {
         log.debug("MainValuesService.appendMetaInformation");
 
         final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesService.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -16,11 +16,7 @@
 import java.util.Date;
 import java.util.List;
 
-import org.dive4elements.artifacts.CallMeta;
-import org.dive4elements.artifacts.GlobalContext;
-import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
 import org.dive4elements.artifacts.common.utils.DateUtils;
-import org.dive4elements.artifacts.common.utils.XMLUtils;
 import org.dive4elements.river.backend.SessionHolder;
 import org.dive4elements.river.model.Gauge;
 import org.dive4elements.river.model.MainValue;
@@ -34,7 +30,6 @@
 import org.dive4elements.river.model.sinfo.DailyDischargeValue.OrderByField;
 import org.dive4elements.river.utils.DoubleUtil;
 import org.hibernate.Session;
-import org.w3c.dom.Document;
 
 import gnu.trove.TDoubleArrayList;
 
@@ -44,80 +39,14 @@
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class DynamicMainValuesService extends AbstractMainValuesService {
+public class DynamicMainValuesService extends AbstractDynamicMainValuesService {
 
     private static final long serialVersionUID = 1L;
 
-    private static final String XPATH_START_YEAR = "/art:mainvalues/art:startYear/text()";
-
-    private static final String XPATH_END_YEAR = "/art:mainvalues/art:endYear/text()";
-
-    @Override
-    public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) {
-        try {
-
-            final River river = getRequestedRiver(data);
-            final Gauge gauge = getRequestedGauge(data, river);
-            final Date startTime = getRequestedStartYear(data);
-            final Date endTime = getRequestedEndYear(data);
-
-            final List<MainValue> mainValues = getMainValues(river, gauge, startTime, endTime);
-
-            return buildDocument(river, gauge, mainValues, context);
-        }
-        catch (final MainValuesServiceException e) {
-            // e.printStackTrace();
-            return error(e.getMessage());
-        }
-        catch (final Exception e) {
-            e.printStackTrace();
-            return error(e.getMessage());
-        }
-    }
-
-    private Date getRequestedStartYear(final Document data) throws MainValuesServiceException {
-
-        final String startStr = XMLUtils.xpathString(data, XPATH_START_YEAR, ArtifactNamespaceContext.INSTANCE);
-
-        if (startStr == null)
-            throw new MainValuesServiceException("no start year");
-
-        try {
-            final int year = Integer.parseInt(startStr);
-            final Calendar cal = Calendar.getInstance();
-            cal.clear();
-            cal.set(year, 0, 1);
-            return cal.getTime();
-        }
-        catch (final NumberFormatException e) {
-            e.printStackTrace();
-            throw new MainValuesServiceException("invalid start year");
-        }
-    }
-
-    private Date getRequestedEndYear(final Document data) throws MainValuesServiceException {
-
-        final String endStr = XMLUtils.xpathString(data, XPATH_END_YEAR, ArtifactNamespaceContext.INSTANCE);
-
-        if (endStr == null)
-            throw new MainValuesServiceException("no end year");
-
-        try {
-            final int year = Integer.parseInt(endStr);
-            final Calendar cal = Calendar.getInstance();
-            cal.clear();
-            cal.set(year, 11, 31);
-            return cal.getTime();
-        }
-        catch (final NumberFormatException e) {
-            e.printStackTrace();
-            throw new MainValuesServiceException("invalid end year");
-        }
-    }
-
     /**
      * Computes a gauge's main values for a period of time based on its daily discharges stored in the database
      */
+    @Override
     protected List<MainValue> getMainValues(final River river, final Gauge gauge, final Date startTime, final Date endTime) throws MainValuesServiceException {
 
         final List<MainValue> mainValues = new ArrayList<>();
@@ -135,7 +64,7 @@
         final List<DailyDischargeValue> qdvs = DailyDischargeValue.getValues(gauge, startTime, endTime, OrderByField.DAY);
         if (qdvs.isEmpty())
             throw new MainValuesServiceException("no daily discharge values for gauge " + gauge.getName() + " in the requested time period");
-        // return; // TODO Fehlermeldung
+        // return;
 
         // Build yearly aggregates
         final TDoubleArrayList mnqs = new TDoubleArrayList();
@@ -152,8 +81,7 @@
                 mqcnt++;
                 if (i == qdvs.size() - 1)
                     mqs.set(j, mqs.get(j) / mqcnt);
-            }
-            else {
+            } else {
                 // Complete mq aggregation
                 if (mqcnt >= 1) {
                     mqs.set(j, mqs.get(j) / mqcnt);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,269 @@
+/* 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.services;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.GlobalContext;
+import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.services.AbstractMainValuesService.MainValuesServiceException;
+import org.dive4elements.river.model.Gauge;
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.model.sinfo.DailyDischargeValue;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This service returns the main values of a river's gauge based on the start
+ * and end point of the river.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DynamicMainValuesTimeRangeDeterminationService extends D4EService {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ROOT_NODE = "dynamic-mainvalues-input";
+
+    private static final Long DATE_DELTA_ERROR_MSG = (long) (60 * 60 * 24 * 1000);
+
+    public static final class ServiceException extends Exception {
+
+        private static final long serialVersionUID = 1L;
+
+        public ServiceException(final String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Computes a gauge's main values for a period of time based on its daily discharges stored in the database
+     *
+     * @throws Exception
+     */
+
+    private static class GaugeInfoResult {
+        private final String globalErrorMsg;
+        private final List<GaugeInfo> gaugeInfos;
+
+        private GaugeInfoResult(final List<GaugeInfo> gaugeInfos, final String globalErrorMsg) {
+            this.gaugeInfos = gaugeInfos;
+            this.globalErrorMsg = globalErrorMsg;
+        }
+
+        private static class GaugeInfo {
+            private final String errorMsg;
+            private final Gauge gauge;
+            private final Date startdate;
+            private final Date enddate;
+
+            public GaugeInfo(final String errorMsg, final Gauge gauge, final Date startdate, final Date enddate) {
+                this.errorMsg = errorMsg;
+                this.gauge = gauge;
+                this.startdate = startdate;
+                this.enddate = enddate;
+            }
+        }
+    }
+
+    private GaugeInfoResult getCommonTimeRangeForGauges(final List<Gauge> gauges, final Date startTime, final Date endTime, final CallMeta meta)
+            throws ServiceException {
+
+        // Query the gauge's daily Q values
+        final List<GaugeInfoResult.GaugeInfo> gaugeResults = new ArrayList<>();
+        Date min = startTime;
+        Date max = endTime;
+
+        for (final Gauge gauge : gauges) {
+
+            final List<DailyDischargeValue> qdvsGlobal = DailyDischargeValue.getGlobalMinMax(gauge);
+            if (qdvsGlobal == null) {
+
+                gaugeResults.add(new GaugeInfoResult.GaugeInfo(getMsg(meta, "bundu.wst_no_data_at_all"), gauge, null, null));
+                // TODO : wenn der Workflow abgebrochen werden soll, GlobalErrorMsg setzen, dass mind. ein Pegel überhaupt keine Daten
+                // hat (der Mechnismus auf Client-Seite ist schon implementiert)
+
+                continue;
+            }
+            assert qdvsGlobal.size() == 2;
+            final Date minGlobalForGauge = qdvsGlobal.get(0).getDay();
+            final Date maxGlobalForGauge = qdvsGlobal.get(1).getDay();
+
+            if (minGlobalForGauge.getTime() > startTime.getTime())
+                min = minGlobalForGauge;
+
+            if (maxGlobalForGauge.getTime() < endTime.getTime())
+                max = maxGlobalForGauge;
+
+            String errormsg = null;
+            if ((maxGlobalForGauge.getTime() < endTime.getTime()) || (minGlobalForGauge.getTime() > startTime.getTime()))
+                errormsg = makeDoesNotCoverErrorMsg(minGlobalForGauge, maxGlobalForGauge, meta);
+
+            gaugeResults.add(new GaugeInfoResult.GaugeInfo(errormsg, gauge, min, max));
+        }
+
+        // common Range and correct errorMsg
+        final List<GaugeInfoResult.GaugeInfo> gaugeResultsSecondTurn = new ArrayList<>();
+        for (final GaugeInfoResult.GaugeInfo gi : gaugeResults) {
+            gaugeResultsSecondTurn
+                    .add(new GaugeInfoResult.GaugeInfo(gi.errorMsg, gi.gauge, gi.startdate != null ? min : null, gi.enddate != null ? max : null));
+        }
+        final String globalErrorMsg = (min.getTime() > max.getTime()) ? getMsg(meta, "bundu.wst.gauge_timeranges_disjoint") : "";
+        final GaugeInfoResult result = new GaugeInfoResult(gaugeResultsSecondTurn, globalErrorMsg);
+
+        return result;
+    }
+
+    private String makeDoesNotCoverErrorMsg(final Date start, final Date end, final CallMeta meta) {
+        final Calendar cal = Calendar.getInstance();
+        cal.setTime(start);
+        final String startyear = String.valueOf(cal.get(Calendar.YEAR));
+        cal.setTime(end);
+        final String endyear = String.valueOf(cal.get(Calendar.YEAR));
+        return Resources.getMsg(meta, "bundu.wst.range_does_not_cover", new Object[] { startyear, endyear });
+    }
+
+    @Override
+    public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) {
+        try {
+            final River river = AbstractMainValuesService.getRequestedRiver(data, "/art:" + this.ROOT_NODE + "/art:river/text()");
+            final List<Gauge> gauges = getRequestedGauges(data, river, callMeta);
+            final Date start = getRequestedStartYear(data, "/art:" + this.ROOT_NODE + "/art:startYear/text()");
+            final Date end = getRequestedEndYear(data, "/art:" + this.ROOT_NODE + "/art:endYear/text()");
+
+            final GaugeInfoResult result = getCommonTimeRangeForGauges(gauges, start, end, callMeta);
+
+            return buildDocument(result, context, callMeta);
+        }
+        catch (final ServiceException | MainValuesServiceException e) {
+            e.printStackTrace();
+            return AbstractMainValuesService.error(e.getMessage());
+        }
+    }
+
+    public static final Date getRequestedEndYear(final Document data, final String XPATH_END_YEAR) throws MainValuesServiceException {
+
+        final String endStr = XMLUtils.xpathString(data, XPATH_END_YEAR, ArtifactNamespaceContext.INSTANCE);
+
+        if (endStr == null)
+            throw new MainValuesServiceException("no end year"); // should not happen
+
+        try {
+            final int year = Integer.parseInt(endStr);
+
+            // FIXME: timezone? probably must match timezone of database
+            final Calendar cal = Calendar.getInstance();
+            cal.clear();
+            cal.set(year, 11, 31);
+            return cal.getTime();
+        }
+        catch (final NumberFormatException e) {
+            e.printStackTrace();
+            throw new MainValuesServiceException("invalid end year"); // should not happen
+        }
+    }
+
+    public static final Date getRequestedStartYear(final Document data, final String XPATH_START_YEAR) throws MainValuesServiceException {
+
+        final String startStr = XMLUtils.xpathString(data, XPATH_START_YEAR, ArtifactNamespaceContext.INSTANCE);
+
+        if (startStr == null)
+            throw new MainValuesServiceException("no start year");// should not happen
+
+        try {
+            final int year = Integer.parseInt(startStr);
+
+            // FIXME: timezone? probably must match timezone of database
+            final Calendar cal = Calendar.getInstance();
+            cal.clear();
+            cal.set(year, 0, 1);
+            return cal.getTime();
+        }
+        catch (final NumberFormatException e) {
+            e.printStackTrace();
+            throw new MainValuesServiceException("invalid start year"); // should not happen
+        }
+    }
+
+    private Document buildDocument(final GaugeInfoResult result, final GlobalContext context, final CallMeta meta) {
+
+        final Document doc = XMLUtils.newDocument();
+
+        final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        final Element rootEl = cr.create(ROOT_NODE);
+
+        doc.appendChild(rootEl);
+
+        final Element globalErrElement = cr.create("global-error-msg");
+        globalErrElement.setTextContent(result.globalErrorMsg);
+        rootEl.appendChild(globalErrElement);
+
+        final List<GaugeInfoResult.GaugeInfo> values = result.gaugeInfos;
+
+        for (final GaugeInfoResult.GaugeInfo gauge : values) {
+            final Element gaugeElement = cr.create("gauge");
+            cr.addAttr(gaugeElement, "name", gauge.gauge.getName());
+            if (gauge.startdate != null)
+                cr.addAttr(gaugeElement, "date-from", String.valueOf(gauge.startdate.getTime()));
+
+            if (gauge.enddate != null)
+                cr.addAttr(gaugeElement, "date-to", String.valueOf(gauge.enddate.getTime()));
+
+            if (gauge.errorMsg != null)
+                cr.addAttr(gaugeElement, "error-message", gauge.errorMsg);
+
+            rootEl.appendChild(gaugeElement);
+        }
+
+        return doc;
+
+    }
+
+    final Element buildElement(final ElementCreator cr, final String type, final Date date) {
+        final Element el = cr.create(type);
+        cr.addAttr(el, "value", String.valueOf(date.getTime()));
+        return el;
+    }
+
+    private static final List<Gauge> getRequestedGauges(final Document data, final River river, final CallMeta meta) throws ServiceException {
+
+        final NodeList gaugeNodes = data.getElementsByTagNameNS(ArtifactNamespaceContext.NAMESPACE_URI, "gauge");
+
+        final List<Gauge> gauges = new ArrayList<>();
+
+        for (int i = 0; i < gaugeNodes.getLength(); i++) {
+            final Element gaugeElt = (Element) gaugeNodes.item(i);
+
+            final String gaugeName = (String) XMLUtils.xpath(gaugeElt, "text()", XPathConstants.STRING);
+            final Gauge gauge = Gauge.getGaugeByNameAndRiver(gaugeName, river);
+            if (gauge != null)
+                gauges.add(gauge);
+            else {
+                throw new ServiceException("bundu_wst_error_reading_gauges");
+            }
+        }
+
+        return gauges;
+    }
+
+    private static String getMsg(final CallMeta meta, final String key) {
+        return Resources.getMsg(meta, key);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -34,7 +34,7 @@
     @Override
     public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) {
         try {
-            final River river = getRequestedRiver(data);
+            final River river = getRequestedRiver(data, "/art:mainvalues/art:river/text()");
             final Gauge gauge = getRequestedGauge(data, river);
 
             final List<MainValue> mainValues = getMainValues(river, gauge);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java	Wed Aug 15 13:59:09 2018 +0200
@@ -20,7 +20,7 @@
 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
-import org.dive4elements.river.artifacts.uinfo.vegetationzones.VegetationZone;
+import org.dive4elements.river.artifacts.uinfo.vegetationzones.VegetationZoneServerClientXChange;
 import org.dive4elements.river.model.River;
 
 /**
@@ -50,7 +50,7 @@
         final String url = indurax.getWMSUrl();
         final Integer year = indurax.getYear(); // null bei year -> Integer
         final String zonesRaw = indurax.getVegZones();
-        final List<VegetationZone> zones = VegetationZone.parse(zonesRaw);
+        final List<VegetationZoneServerClientXChange> zones = VegetationZoneServerClientXChange.parse(zonesRaw);
         final String scenarioUrl = indurax.getWMSScenarioUrl();
         final String scenarioStr = String.valueOf(indurax.getDwspl());
 
--- a/artifacts/src/main/resources/messages.properties	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Wed Aug 15 13:59:09 2018 +0200
@@ -1294,6 +1294,10 @@
 
 bundu.wst.export.csv.meta.header.bezugswst = Bezugswasserstand
 bundu.wst.export.pdf.meta.header.bezugswst = Bezugs-wasserstand
+bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor.
+bundu.wst.range_does_not_cover = Die Abflussganglinie ({0}-{1}) deckt nicht den Bezugszeitraum ab. 
+bundu.wst.error_reading_gauges = Fehler beim Abruf des Pegels aus der Datenbank.
+bundu.wst.gauge_timeranges_disjoint = Der Bezugszeitraum konnte nicht auf die vorhandenen Abflusswerte eingeschr\u00e4nkt werden. 
 
 common.client.ui.selection = Selection
 common.client.ui.from = from
--- a/artifacts/src/main/resources/messages_de.properties	Wed Aug 15 13:22:00 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Wed Aug 15 13:59:09 2018 +0200
@@ -1294,7 +1294,11 @@
 
 bundu.wst.export.csv.meta.header.bezugswst = Bezugswasserstand
 bundu.wst.export.pdf.meta.header.bezugswst = Bezugs-wasserstand
-  
+bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor.
+bundu.wst.range_does_not_cover = Die Abflussganglinie ({0}-{1}) deckt nicht den Bezugszeitraum ab. 
+bundu.wst.error_reading_gauges = Fehler beim Abruf des Pegels aus der Datenbank.
+bundu.wst.gauge_timeranges_disjoint = Der Bezugszeitraum konnte nicht auf die vorhandenen Abflusswerte eingeschr\u00e4nkt werden. 
+
 common.client.ui.selection = Auswahl
 common.client.ui.from = von
 common.client.ui.to = bis
--- a/backend/src/main/java/org/dive4elements/river/model/Gauge.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/Gauge.java	Wed Aug 15 13:59:09 2018 +0200
@@ -8,48 +8,42 @@
 
 package org.dive4elements.river.model;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
-
-import java.io.Serializable;
-
 import java.util.List;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
 import javax.persistence.Id;
-import javax.persistence.Table;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Column;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
 import javax.persistence.SequenceGenerator;
-import javax.persistence.GenerationType;
-import javax.persistence.JoinColumn;
-import javax.persistence.OneToOne;
-import javax.persistence.OneToMany;
-
-import org.hibernate.Session;
-import org.hibernate.Query;
+import javax.persistence.Table;
 
 import org.apache.log4j.Logger;
-
 import org.dive4elements.river.backend.SessionHolder;
+import org.hibernate.Query;
+import org.hibernate.Session;
 
 /** Database-mapped Gauge with all info about it. */
 @Entity
 @Table(name = "gauges")
-public class Gauge
-implements   Serializable, Comparable<Gauge>
-{
+public class Gauge implements Serializable, Comparable<Gauge> {
     private static final Logger log = Logger.getLogger(Gauge.class);
 
     public static final int MASTER_DISCHARGE_TABLE = 0;
 
-    private Integer    id;
-    private String     name;
-    private River      river;
+    private Integer id;
+    private String name;
+    private River river;
     private BigDecimal station;
     private BigDecimal aeo;
     private BigDecimal datum;
-    private Long       officialNumber;
-    private Range      range;
+    private Long officialNumber;
+    private Range range;
 
     private List<DischargeTable> dischargeTables;
 
@@ -59,247 +53,226 @@
     public Gauge() {
     }
 
-    public Gauge(
-        String     name,
-        River      river,
-        BigDecimal station,
-        BigDecimal aeo,
-        BigDecimal datum,
-        Long       officialNumber,
-        Range      range
-    ) {
-        this.name            = name;
-        this.river           = river;
-        this.station         = station;
-        this.aeo             = aeo;
-        this.datum           = datum;
-        this.officialNumber  = officialNumber;
-        this.range           = range;
+    public Gauge(final String name, final River river, final BigDecimal station, final BigDecimal aeo, final BigDecimal datum, final Long officialNumber,
+            final Range range) {
+        this.name = name;
+        this.river = river;
+        this.station = station;
+        this.aeo = aeo;
+        this.datum = datum;
+        this.officialNumber = officialNumber;
+        this.range = range;
     }
 
     @Id
-    @SequenceGenerator(
-        name           = "SEQUENCE_GAUGES_ID_SEQ",
-        sequenceName   = "GAUGES_ID_SEQ",
-        allocationSize = 1)
-    @GeneratedValue(
-        strategy  = GenerationType.SEQUENCE,
-        generator = "SEQUENCE_GAUGES_ID_SEQ")
+    @SequenceGenerator(name = "SEQUENCE_GAUGES_ID_SEQ", sequenceName = "GAUGES_ID_SEQ", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_GAUGES_ID_SEQ")
     @Column(name = "id")
     public Integer getId() {
-        return id;
+        return this.id;
     }
 
-    public void setId(Integer id) {
+    public void setId(final Integer id) {
         this.id = id;
     }
 
     @OneToOne
-    @JoinColumn(name = "river_id" )
+    @JoinColumn(name = "river_id")
     public River getRiver() {
-        return river;
+        return this.river;
     }
 
-    public void setRiver(River river) {
+    public void setRiver(final River river) {
         this.river = river;
     }
 
     @Column(name = "name")
     public String getName() {
-        return name;
+        return this.name;
     }
 
-    public void setName(String name) {
+    public void setName(final String name) {
         this.name = name;
     }
 
     @Column(name = "station") // FIXME: type mapping needed
     public BigDecimal getStation() {
-        return station;
+        return this.station;
     }
 
-    public void setStation(BigDecimal station) {
+    public void setStation(final BigDecimal station) {
         this.station = station;
     }
 
     @Column(name = "aeo") // FIXME: type mapping needed
     public BigDecimal getAeo() {
-        return aeo;
+        return this.aeo;
     }
 
-    public void setAeo(BigDecimal aeo) {
+    public void setAeo(final BigDecimal aeo) {
         this.aeo = aeo;
     }
 
     @Column(name = "datum") // FIXME: type mapping needed
     public BigDecimal getDatum() {
-        return datum;
+        return this.datum;
     }
 
-    public void setDatum(BigDecimal datum) {
+    public void setDatum(final BigDecimal datum) {
         this.datum = datum;
     }
 
     @Column(name = "official_number")
     public Long getOfficialNumber() {
-        return officialNumber;
+        return this.officialNumber;
     }
 
-    public void setOfficialNumber(Long officialNumber) {
+    public void setOfficialNumber(final Long officialNumber) {
         this.officialNumber = officialNumber;
     }
 
     @OneToOne
-    @JoinColumn(name = "range_id" )
+    @JoinColumn(name = "range_id")
     public Range getRange() {
-        return range;
+        return this.range;
     }
 
-    public void setRange(Range range) {
+    public void setRange(final Range range) {
         this.range = range;
     }
 
     @OneToMany
     @JoinColumn(name = "gauge_id")
     public List<DischargeTable> getDischargeTables() {
-        return dischargeTables;
+        return this.dischargeTables;
     }
 
-    public void setDischargeTables(List<DischargeTable> dischargeTables) {
+    public void setDischargeTables(final List<DischargeTable> dischargeTables) {
         this.dischargeTables = dischargeTables;
     }
 
-
     /**
      * Returns min and max W values of this gauge.
      *
      * @return the min and max W value of this gauge [min,max].
      */
     public double[] determineMinMaxW() {
-        Session session = SessionHolder.HOLDER.get();
+        final Session session = SessionHolder.HOLDER.get();
 
-        DischargeTable dischargeTable = fetchMasterDischargeTable();
+        final DischargeTable dischargeTable = fetchMasterDischargeTable();
 
         if (dischargeTable == null) {
             return null;
         }
 
-        Query query  = session.createQuery(
-            "select min(w) as min, max(w) as max from DischargeTableValue " +
-            "where table_id =:table");
+        final Query query = session.createQuery("select min(w) as min, max(w) as max from DischargeTableValue " + "where table_id =:table");
         query.setParameter("table", dischargeTable.getId());
 
-        List<?> results = query.list();
+        final List<?> results = query.list();
         if (results.isEmpty()) {
             log.error("No values in discharge table found.");
             return null;
         }
 
-        Object[] result  = (Object[])results.get(0);
+        final Object[] result = (Object[]) results.get(0);
 
-        BigDecimal a = (BigDecimal)result[0];
-        BigDecimal b = (BigDecimal)result[1];
+        final BigDecimal a = (BigDecimal) result[0];
+        final BigDecimal b = (BigDecimal) result[1];
 
-        return a != null && b != null
-            ? new double [] { a.doubleValue(), b.doubleValue() }
-            : null;
+        return a != null && b != null ? new double[] { a.doubleValue(), b.doubleValue() } : null;
     }
 
     @OneToMany
     @JoinColumn(name = "gauge_id")
     public List<MainValue> getMainValues() {
-        return mainValues;
+        return this.mainValues;
     }
 
-    public void setMainValues(List<MainValue> mainValues) {
+    public void setMainValues(final List<MainValue> mainValues) {
         this.mainValues = mainValues;
     }
 
-    public static Gauge getGaugeByOfficialNumber(long number) {
-        Session session = SessionHolder.HOLDER.get();
+    public static Gauge getGaugeByOfficialNumber(final long number) {
+        final Session session = SessionHolder.HOLDER.get();
 
-        Query query = session.createQuery(
-            "from Gauge where officialNumber=:number");
+        final Query query = session.createQuery("from Gauge where officialNumber=:number");
 
         query.setParameter("number", number);
 
-        List<Gauge> results = query.list();
+        final List<Gauge> results = query.list();
 
         return results.isEmpty() ? null : results.get(0);
     }
 
-    public static Gauge getGaugeByOfficialNumber(
-        long number,
-        String river_name
-    ) {
-        Session session = SessionHolder.HOLDER.get();
+    public static Gauge getGaugeByOfficialNumber(final long number, final String river_name) {
+        final Session session = SessionHolder.HOLDER.get();
 
-        Query query = session.createQuery(
-            "from Gauge as gau " +
-            "where gau.officialNumber=:number and gau.river.name=:river_name");
+        final Query query = session.createQuery("from Gauge as gau " + "where gau.officialNumber=:number and gau.river.name=:river_name");
 
         query.setParameter("number", number);
         query.setParameter("river_name", river_name);
 
-        List<Gauge> results = query.list();
+        final List<Gauge> results = query.list();
 
         return results.isEmpty() ? null : results.get(0);
     }
 
+    public static Gauge getGaugeByNameAndRiver(final String gauge_name, final River river) {
+        final Session session = SessionHolder.HOLDER.get();
+
+        final Query query = session.createQuery("from Gauge as gau " + "where gau.name=:name and gau.river=:river");
+
+        query.setParameter("name", gauge_name);
+        query.setParameter("river", river);
+
+        final List<Gauge> results = query.list();
+
+        return results.isEmpty() ? null : results.get(0);
+    }
 
     public DischargeTable fetchMasterDischargeTable() {
-        Session session = SessionHolder.HOLDER.get();
+        final Session session = SessionHolder.HOLDER.get();
 
-        Query query = session.createQuery(
-            "from DischargeTable " +
-            "where kind = 0 " +
-            "and gauge = :gauge");
+        final Query query = session.createQuery("from DischargeTable " + "where kind = 0 " + "and gauge = :gauge");
 
         query.setParameter("gauge", this);
 
-        List<Object> results = query.list();
+        final List<Object> results = query.list();
 
-        return results.isEmpty()
-            ? null
-            : (DischargeTable)results.get(0);
+        return results.isEmpty() ? null : (DischargeTable) results.get(0);
     }
 
     /**
      * Returns an array of [days, qs] necessary to create duration curves.
      *
      * @return a 2dim array of [days, qs] where days is an int[] and qs is
-     * an double[].
+     *         an double[].
      */
     public Object[] fetchDurationCurveData() {
-        Session session = SessionHolder.HOLDER.get();
+        final Session session = SessionHolder.HOLDER.get();
 
-        Query query = session.createQuery(
-            "select cast(nmv.name as integer) as days, mv.value as q " +
-            "from MainValue as mv " +
-            "join mv.mainValue as nmv " +
-            "join nmv.type mvt " +
-            "where mvt.name = 'D' and mv.gauge.id = :gauge_id " +
-            "order by days");
+        final Query query = session.createQuery("select cast(nmv.name as integer) as days, mv.value as q " + "from MainValue as mv "
+                + "join mv.mainValue as nmv " + "join nmv.type mvt " + "where mvt.name = 'D' and mv.gauge.id = :gauge_id " + "order by days");
 
         query.setParameter("gauge_id", getId());
 
-        List<Object> results = query.list();
-        int[]        days    = new int[results.size()];
-        double[]     qs      = new double[results.size()];
+        final List<Object> results = query.list();
+        final int[] days = new int[results.size()];
+        final double[] qs = new double[results.size()];
 
         int idx = 0;
 
-        for (Object obj: results) {
-            Object[] arr = (Object[]) obj;
+        for (final Object obj : results) {
+            final Object[] arr = (Object[]) obj;
 
             try {
-                int  day = ((Integer)    arr[0]).intValue();
-                double q = ((BigDecimal) arr[1]).doubleValue();
+                final int day = ((Integer) arr[0]).intValue();
+                final double q = ((BigDecimal) arr[1]).doubleValue();
 
                 days[idx] = day;
                 qs[idx++] = q;
             }
-            catch (NumberFormatException nfe) {
+            catch (final NumberFormatException nfe) {
             }
         }
 
@@ -312,44 +285,36 @@
      * @return the MaxMinWQ object representing the calculated values
      */
     public MinMaxWQ fetchMaxMinWQ() {
-        Session session = SessionHolder.HOLDER.get();
+        final Session session = SessionHolder.HOLDER.get();
 
-        Query query = session.createQuery(
-            "select max(mv.value) as max, min(mv.value) as min " +
-            "from MainValue as mv " +
-            "join mv.mainValue as nmv " +
-            "join nmv.type mvt " +
-            "where mvt.name in ('W', 'Q') " +
-            "and mv.gauge.id = :gauge_id " +
-            "group by mvt.name order by mvt.name"
-            );
+        final Query query = session.createQuery("select max(mv.value) as max, min(mv.value) as min " + "from MainValue as mv " + "join mv.mainValue as nmv "
+                + "join nmv.type mvt " + "where mvt.name in ('W', 'Q') " + "and mv.gauge.id = :gauge_id " + "group by mvt.name order by mvt.name");
 
         query.setParameter("gauge_id", getId());
 
-        List<Object> results = query.list();
+        final List<Object> results = query.list();
         if (results.isEmpty()) {
             // No values found
             return new MinMaxWQ();
         }
 
         Object[] arr = (Object[]) results.get(0);
-        BigDecimal maxw = (BigDecimal)arr[0];
-        BigDecimal minw = (BigDecimal)arr[1];
+        final BigDecimal maxw = (BigDecimal) arr[0];
+        final BigDecimal minw = (BigDecimal) arr[1];
         BigDecimal maxq = null;
         BigDecimal minq = null;
 
-
         if (results.size() > 1) {
             arr = (Object[]) results.get(1);
-            maxq = (BigDecimal)arr[0];
-            minq = (BigDecimal)arr[1];
+            maxq = (BigDecimal) arr[0];
+            minq = (BigDecimal) arr[1];
         }
 
         return new MinMaxWQ(minw, maxw, minq, maxq);
     }
 
     @Override
-    public int compareTo(Gauge o) {
+    public int compareTo(final Gauge o) {
         return getName().compareTo(o.getName());
     }
 }
--- a/backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java	Wed Aug 15 13:59:09 2018 +0200
@@ -11,6 +11,7 @@
 package org.dive4elements.river.model.sinfo;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -29,7 +30,6 @@
 import org.hibernate.Query;
 import org.hibernate.Session;
 
-
 /**
  * Hibernate binding for the DB table daily_discharge_values
  *
@@ -62,7 +62,6 @@
 
     private Double discharge;
 
-
     /***** CONSTRUCTORS *****/
 
     public DailyDischargeValue() {
@@ -81,7 +80,6 @@
         this(dailyDischarge, day, Double.valueOf(discharge));
     }
 
-
     /***** METHODS *****/
 
     @Id
@@ -130,13 +128,33 @@
     public static List<DailyDischargeValue> getValues(final Gauge gauge, final Date startDate, final Date endDate, final OrderByField orderBy) {
         final Session session = SessionHolder.HOLDER.get();
         final String orderField = (orderBy == OrderByField.DISCHARGE) ? "discharge" : "day";
-        final Query query = session.createQuery("SELECT v"
-                + " FROM DailyDischargeValue AS v JOIN v.dailyDischarge AS s"
-                + " WHERE (s.gauge.id=:gaugeid) AND (v.day BETWEEN :startDate AND :endDate)"
-                + " ORDER BY " + orderField);
+        final Query query = session.createQuery("SELECT v" + " FROM DailyDischargeValue AS v JOIN v.dailyDischarge AS s"
+                + " WHERE (s.gauge.id=:gaugeid) AND (v.day BETWEEN :startDate AND :endDate)" + " ORDER BY " + orderField);
         query.setParameter("gaugeid", gauge.getId());
         query.setParameter("startDate", startDate);
         query.setParameter("endDate", endDate);
         return query.list();
     }
+
+    /**
+     * Selects from the database the daily discharge, puts the first and the last into a List (min, max day)
+     */
+    public static List<DailyDischargeValue> getGlobalMinMax(final Gauge gauge) {
+        final Session session = SessionHolder.HOLDER.get();
+        final Query query = session
+                .createQuery("SELECT v" + " FROM DailyDischargeValue AS v JOIN v.dailyDischarge AS s" + " WHERE (s.gauge.id=:gaugeid)  ORDER BY day");
+        query.setParameter("gaugeid", gauge.getId());
+        return minMaxFromDbResultHelper(query.list());
+    }
+
+    private static List<DailyDischargeValue> minMaxFromDbResultHelper(final List<DailyDischargeValue> values) {
+        if (values != null && values.size() > 1) {
+            final List<DailyDischargeValue> newList = new ArrayList<>();
+            newList.add(values.get(0));
+            newList.add(values.get(values.size() - 1));
+            return newList;
+        }
+        return null;
+
+    }
 }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesService.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -8,6 +8,8 @@
 
 package org.dive4elements.river.client.client.services;
 
+import java.util.Date;
+
 import org.dive4elements.river.client.shared.exceptions.ServerException;
 import org.dive4elements.river.client.shared.model.WQInfoObject;
 
@@ -25,5 +27,5 @@
     /**
      * This method returns a list of DistanceInfoObjects for a specific river.
      */
-    WQInfoObject[] getWQInfo(String locale, String river, double start, double end, int startYear, int endYear) throws ServerException;
+    WQInfoObject[] getWQInfo(String locale, String river, double start, double end, Date startDate, Date endDate) throws ServerException;
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesServiceAsync.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesServiceAsync.java	Wed Aug 15 13:59:09 2018 +0200
@@ -9,6 +9,8 @@
  */
 package org.dive4elements.river.client.client.services;
 
+import java.util.Date;
+
 import org.dive4elements.river.client.shared.model.WQInfoObject;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -17,5 +19,5 @@
  * @author Domenico Nardi Tironi
  */
 public interface DynamicMainValuesServiceAsync {
-    void getWQInfo(String locale, String river, double start, double end, int startYear, int endYear, AsyncCallback<WQInfoObject[]> callback);
+    void getWQInfo(String locale, String river, double startKm, double endKm, Date start, Date end, AsyncCallback<WQInfoObject[]> callback);
 }
\ 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/services/DynamicMainValuesTimeRangeDeterminationService.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,32 @@
+/* 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.services;
+
+import org.dive4elements.river.client.shared.exceptions.ServerException;
+import org.dive4elements.river.client.shared.model.GaugeInfoObject;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+/**
+ *
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+@RemoteServiceRelativePath("dynamic-mainvalues-timerange-determination")
+public interface DynamicMainValuesTimeRangeDeterminationService extends RemoteService {
+
+    /**
+     * This method returns a list of DistanceInfoObjects for a specific river.
+     *
+     * @throws ServerException
+     */
+    GaugeInfoObject[] getGaugeInfo(String locale, String river, final String[] gauges, int startYear, int endYear) throws ServerException;
+
+}
\ 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/services/DynamicMainValuesTimeRangeDeterminationServiceAsync.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,21 @@
+/** 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.client.services;
+
+import org.dive4elements.river.client.shared.model.GaugeInfoObject;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public interface DynamicMainValuesTimeRangeDeterminationServiceAsync {
+    void getGaugeInfo(String locale, String river, final String[] gauges, int startDate, int endDate, AsyncCallback<GaugeInfoObject[]> callback);
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java	Wed Aug 15 13:59:09 2018 +0200
@@ -13,7 +13,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.FLYSConstants;
 import org.dive4elements.river.client.client.ui.wq.QDTable;
 import org.dive4elements.river.client.client.ui.wq.WTable;
@@ -23,12 +22,12 @@
 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.GaugeInfoObject;
 import org.dive4elements.river.client.shared.model.WQDataItem;
 import org.dive4elements.river.client.shared.model.WQInfoObject;
 import org.dive4elements.river.client.shared.model.WQInfoRecord;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.smartgwt.client.data.Record;
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
@@ -85,6 +84,11 @@
     /** Tabs in inputhelper area. */
     protected TabSet tabs;
 
+    private Canvas submit;
+
+    private final List<String> gaugeNames = new ArrayList<String>();
+    private final Map<String, Double[]> gaugeNamesRange = new HashMap<String, Double[]>();
+
     public AbstractWQAdaptedInputPanel() {
         this.wqranges = new HashMap<String, DoubleArrayPanel>();
         this.qranges = new HashMap<String, double[]>();
@@ -92,6 +96,14 @@
         this.qdTables = new ArrayList<QDTable>();
     }
 
+    protected final Map<String, Double[]> getGaugeNamesRange() {
+        return this.gaugeNamesRange;
+    }
+
+    protected final String[] getGaugeNames() {
+        return this.gaugeNames.toArray(new String[this.gaugeNames.size()]);
+    }
+
     /** Inits the helper panel. */
     // TODO duplicate in WQInputPanel
     protected void initHelperPanel() {
@@ -113,7 +125,7 @@
         readGaugeRanges(data);
         initHelperPanel();
 
-        final Canvas submit = getNextButton();
+        this.submit = getNextButton();
         final Canvas widget = createWidget(data);
         final Label label = new Label(this.MSG.wqadaptedTitle());
 
@@ -125,7 +137,7 @@
 
         layout.addMember(label);
         layout.addMember(widget);
-        layout.addMember(submit);
+        layout.addMember(this.submit);
 
         fetchWQData();
 
@@ -136,6 +148,10 @@
         return layout;
     }
 
+    protected final Canvas getSubmitBtn() {
+        return this.submit;
+    }
+
     protected abstract void createTabs();
 
     protected abstract void beforeCreate(final DataList data);
@@ -359,6 +375,9 @@
                 final String[] startEndKm = item.getLabel().split(";");
                 final Double[] kvp = new Double[] { Double.parseDouble(startEndKm[0]), Double.parseDouble(startEndKm[1]) };
                 this.gaugeRanges.add(kvp);
+                final String gaugeName = item.getStringValue();
+                this.gaugeNames.add(gaugeName);
+                this.gaugeNamesRange.put(gaugeName, kvp);
             }
         }
     }
@@ -433,64 +452,41 @@
     }
 
     /** Get the WQD data from service and stuck them up that tables. */
-    protected void fetchWQData() {
-        final Config config = Config.getInstance();
-        final String locale = config.getLocale();
-
-        final ArtifactDescription adescr = this.artifact.getArtifactDescription();
-        final DataList[] data = adescr.getOldData();
-
-        final String river = getRiverName(data);
-
-        int i = 0;
-
-        // Get Data for respective gauge.
-        for (final Double[] range : this.gaugeRanges) {
-            // Gauge ranges overlap, move start and end a bit closer
-            // to each other.
-            final double rDiff = (range[1] - range[0]) / 10d;
-            final int fi = i;
+    protected abstract void fetchWQData();
 
-            final AsyncCallback<WQInfoObject[]> cb = new AsyncCallback<WQInfoObject[]>() {
-                @Override
-                public void onFailure(final Throwable caught) {
-                    GWT.log("Could not recieve wq informations.");
-                    SC.warn(caught.getMessage());
-                }
-
-                @Override
-                public void onSuccess(final WQInfoObject[] wqi) {
-                    final int num = wqi != null ? wqi.length : 0;
-                    GWT.log("Received " + num + " wq informations (" + fi + ".");
+    // protected abstract void callMainValuesService(String locale, String river, double start, double end,
+    // AsyncCallback<WQInfoObject[]> cb);
 
-                    if (num == 0) {
-                        return;
-                    }
+    /** Add Info to helper table for gauge at index gaugeIdx. */
+    public void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx, final GaugeInfoObject gauge) {
+        if (wqi == null) {
+            // this.wTables.get(gaugeIdx).setLoadingDataMessage(""); (keine W-tables vorhanden - wo W-Table benutzt werden, gibt es
+            // ein Popup)
+            final String emptyMsg = gauge.getErrorMessage();
+            final QDTable table = this.qdTables.get(gaugeIdx);
+            table.setEmptyMessage(emptyMsg == null ? "" : emptyMsg);
+            table.redraw();
+        } else {
+            for (final WQInfoObject wi : wqi) {
+                final WQInfoRecord rec = new WQInfoRecord(wi);
 
-                    addWQInfo(wqi, fi);
+                if (wi.getType().equals("W")) {
+                    if (gaugeIdx < this.wTables.size())
+                        this.wTables.get(gaugeIdx).addData(rec);
+                } else { // Q,D,- alle gehören hier rein!
+                    if (gaugeIdx < this.qdTables.size())
+                        this.qdTables.get(gaugeIdx).addData(rec);
                 }
-            };
-
-            callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, cb);
-
-            i++;
+            }
         }
+        if (gauge != null)
+            AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(gaugeIdx).setError(gauge.getErrorMessage());
     }
 
-    protected abstract void callMainValuesService(String locale, String river, double start, double end, AsyncCallback<WQInfoObject[]> cb);
-
-    /** Add Info to helper table for gauge at index gaugeIdx. */
-    private void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx) {
-        for (final WQInfoObject wi : wqi) {
-            final WQInfoRecord rec = new WQInfoRecord(wi);
-
-            if (wi.getType().equals("W")) {
-                if (gaugeIdx < this.wTables.size())
-                    this.wTables.get(gaugeIdx).addData(rec);
-            } else { // Q,D,- alle gehören hier rein!
-                if (gaugeIdx < this.qdTables.size())
-                    this.qdTables.get(gaugeIdx).addData(rec);
-            }
+    public void resetLoadingMessageOfQTable(final String msg) {
+        for (final QDTable table : this.qdTables) {
+            table.setEmptyMessage(msg);
+            table.redraw();
         }
     }
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DoubleArrayPanel.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DoubleArrayPanel.java	Wed Aug 15 13:59:09 2018 +0200
@@ -28,6 +28,8 @@
 
     protected TextItem ti;
 
+    private final StaticTextItem errorItem = new StaticTextItem("error");
+
     private String title;
 
     /** The constant input field name. */
@@ -52,29 +54,41 @@
      * @param focusHandler
      *            The FocueHandler that is used to valide the input.
      */
+
     public DoubleArrayPanel(final String title, final double[] values, final BlurHandler blurHandler, final FocusHandler focusHandler,
-            final TitleOrientation titleOrientation) {
+            final TitleOrientation titleOrientation, final String errorMsg) {
+
         this.title = title;
         this.ti = new TextItem(FIELD_NAME);
         final StaticTextItem sti = new StaticTextItem("staticarray");
+        sti.setColSpan(2);
+
+        this.errorItem.setTitle("");
+        if (errorMsg != null)
+            this.errorItem.setValue(errorMsg);
+
+        this.errorItem.setShowTitle(false);
+        this.errorItem.setVisible(true);
+        this.errorItem.setColSpan(2);
+        sti.setShowTitle(false);
+        sti.setValue(title);
+        sti.setColSpan(1);
 
         this.ti.setShowTitle(false);
-        sti.setShowTitle(false);
-        sti.setValue(title);
-
+        this.ti.setColSpan(1);
         this.ti.addBlurHandler(blurHandler);
         if (focusHandler != null) {
             this.ti.addFocusHandler(focusHandler);
         }
 
         if (titleOrientation == TitleOrientation.RIGHT) {
-            setFields(this.ti, sti);
+            setFields(this.ti, sti, this.errorItem);
         } else {
-            setFields(sti, this.ti);
+            setFields(sti, this.ti, this.errorItem);
         }
 
         setTitleOrientation(titleOrientation);
-        setNumCols(2);
+        setNumCols(5);
 
         if (values == null) {
             return;
@@ -96,6 +110,12 @@
         }
 
         this.ti.setValue(text.toString());
+
+    }
+
+    public DoubleArrayPanel(final String title, final double[] values, final BlurHandler blurHandler, final FocusHandler focusHandler,
+            final TitleOrientation titleOrientation) {
+        this(title, values, blurHandler, focusHandler, titleOrientation, null);
     }
 
     /**
@@ -149,6 +169,10 @@
         this.ti.setValue(current);
     }
 
+    public void setError(final String error) {
+        this.errorItem.setValue(error);
+    }
+
     public boolean validateForm() {
         return validateForm(this.ti);
     }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java	Wed Aug 15 13:59:09 2018 +0200
@@ -14,10 +14,12 @@
 import java.util.List;
 import java.util.Map;
 
+import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.services.WQInfoService;
 import org.dive4elements.river.client.client.services.WQInfoServiceAsync;
 import org.dive4elements.river.client.client.ui.wq.QDTable;
 import org.dive4elements.river.client.client.ui.wq.WTable;
+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;
@@ -385,9 +387,58 @@
         this.tabs.selectTab(inputIndex * 2 + (isWMode() ? 0 : 1));
     }
 
-    @Override
     protected void callMainValuesService(final String locale, final String river, final double start, final double end,
             final AsyncCallback<WQInfoObject[]> cb) {
         this.wqInfoService.getWQInfo(locale, river, start, end, cb);
     }
+
+    @Override
+    protected void fetchWQData() {
+        {
+            final Config config = Config.getInstance();
+            final String locale = config.getLocale();
+
+            final ArtifactDescription adescr = this.artifact.getArtifactDescription();
+            final DataList[] data = adescr.getOldData();
+
+            final String river = getRiverName(data);
+
+            int i = 0;
+
+            // Get Data for respective gauge.
+            for (final Double[] range : this.gaugeRanges) {
+                // Gauge ranges overlap, move start and end a bit closer
+                // to each other.
+                final double rDiff = (range[1] - range[0]) / 10d;
+                final int fi = i;
+                // TODO: HIER MÜSSTE EIN SERVICE HIN, der den größten gemeinsamen zeitlichen Bereich der daily_discharge_values aller
+                // Pegel ermittelt
+
+                final AsyncCallback<WQInfoObject[]> cb = new AsyncCallback<WQInfoObject[]>() {
+                    @Override
+                    public void onFailure(final Throwable caught) {
+                        GWT.log("Could not recieve wq informations.");
+                        SC.warn(caught.getMessage());
+                    }
+
+                    @Override
+                    public void onSuccess(final WQInfoObject[] wqi) {
+                        final int num = wqi != null ? wqi.length : 0;
+                        GWT.log("Received " + num + " wq informations (" + fi + ".");
+
+                        if (num == 0) {
+                            return;
+                        }
+
+                        addWQInfo(wqi, fi, null);
+                    }
+                };
+
+                callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, cb);
+
+                i++;
+            }
+        }
+
+    }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java	Wed Aug 15 13:59:09 2018 +0200
@@ -9,20 +9,26 @@
 package org.dive4elements.river.client.client.ui.bundu;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.services.DynamicMainValuesService;
 import org.dive4elements.river.client.client.services.DynamicMainValuesServiceAsync;
+import org.dive4elements.river.client.client.services.DynamicMainValuesTimeRangeDeterminationService;
+import org.dive4elements.river.client.client.services.DynamicMainValuesTimeRangeDeterminationServiceAsync;
 import org.dive4elements.river.client.client.ui.AbstractWQAdaptedInputPanel;
 import org.dive4elements.river.client.client.ui.DoubleArrayPanel;
 import org.dive4elements.river.client.client.ui.wq.QDTable;
+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;
 import org.dive4elements.river.client.shared.model.DefaultData;
 import org.dive4elements.river.client.shared.model.DefaultDataItem;
+import org.dive4elements.river.client.shared.model.GaugeInfoObject;
 import org.dive4elements.river.client.shared.model.WQDataItem;
 import org.dive4elements.river.client.shared.model.WQInfoObject;
 
@@ -32,6 +38,7 @@
 import com.smartgwt.client.types.TitleOrientation;
 import com.smartgwt.client.types.VerticalAlignment;
 import com.smartgwt.client.types.Visibility;
+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;
@@ -65,6 +72,7 @@
 
     /** Service to fetch W/Q MainValues. */
     private final DynamicMainValuesServiceAsync mainValueService = GWT.create(DynamicMainValuesService.class);
+    private final DynamicMainValuesTimeRangeDeterminationServiceAsync serviceForTime = GWT.create(DynamicMainValuesTimeRangeDeterminationService.class);
 
     private final RadioGroupItem radiogroup = new RadioGroupItem();
 
@@ -351,14 +359,10 @@
         return vlayout;
     }
 
-    @Override
-    protected void callMainValuesService(final String locale, final String river, final double start, final double end,
-            final AsyncCallback<WQInfoObject[]> cb) {
+    protected void callMainValuesService(final String locale, final String river, final double start, final double end, final Date startDate,
+            final Date endDate, final AsyncCallback<WQInfoObject[]> cb) {
 
-        final int startYear = this.bezugsjahr - this.qSeriesLength + 1;
-        final int endYear = this.bezugsjahr;
-
-        this.mainValueService.getWQInfo(locale, river, start, end, startYear, endYear, cb);
+        this.mainValueService.getWQInfo(locale, river, start, end, startDate, endDate, cb);
     }
 
     @Override
@@ -370,4 +374,79 @@
             this.tabs.selectTab(inputIndex);
         }
     }
+
+    @Override
+    protected void fetchWQData() {
+        {
+            final Config config = Config.getInstance();
+            final String locale = config.getLocale();
+
+            final ArtifactDescription adescr = this.artifact.getArtifactDescription();
+            final DataList[] data = adescr.getOldData();
+
+            final String river = getRiverName(data);
+            final int startYear = this.bezugsjahr - this.qSeriesLength;
+            final int endYear = this.bezugsjahr;
+
+            // Gauge ranges overlap, move start and end a bit closer
+            // to each other.
+
+            final AsyncCallback<GaugeInfoObject[]> cb = new AsyncCallback<GaugeInfoObject[]>() {
+                @Override
+                public void onFailure(final Throwable caught) {
+                    GWT.log("Could not recieve wq informations.");
+                    final String msg = caught.getMessage();
+                    resetLoadingMessageOfQTable(msg);
+                    // disable weiter-knopf
+                    getSubmitBtn().disable();
+                    SC.warn(msg);
+                }
+
+                @Override
+                public void onSuccess(final GaugeInfoObject[] result) {
+                    // TODO Auto-generated method stub
+                    final int num = result != null ? result.length : 0;
+                    GWT.log("Received  timeranges for gauges");
+
+                    if (num == 0) {
+                        return;
+                    }
+
+                    for (int i = 0; i < result.length; i++) {
+                        final GaugeInfoObject gauge = result[i];
+                        // Gauge ranges overlap, move start and end a bit closer
+                        // to each other.
+                        final Double[] range = getGaugeNamesRange().get(gauge.getName());
+                        final double rDiff = (range[1] - range[0]) / 10d;
+                        final int fi = i;
+
+                        final AsyncCallback<WQInfoObject[]> cb = new AsyncCallback<WQInfoObject[]>() {
+                            @Override
+                            public void onFailure(final Throwable caught) {
+                                GWT.log("Could not recieve wq informations.");
+                                addWQInfo(null, fi, gauge);
+                            }
+
+                            @Override
+                            public void onSuccess(final WQInfoObject[] wqi) {
+                                final int num = wqi != null ? wqi.length : 0;
+                                GWT.log("Received " + num + " wq informations (" + fi + ".");
+
+                                addWQInfo(wqi, fi, gauge);
+                                if (fi == (result.length - 1))
+                                    getSubmitBtn().enable();
+                            }
+                        };
+                        callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, gauge.getStartTime(), gauge.getStopTime(), cb);
+                    }
+                }
+
+            };
+
+            this.serviceForTime.getGaugeInfo(locale, river, getGaugeNames(), startYear, endYear, cb);
+            getSubmitBtn().disable();
+        }
+
+    }
+
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java	Wed Aug 15 13:59:09 2018 +0200
@@ -66,7 +66,8 @@
 
     private static final long serialVersionUID = 1L;
 
-    protected final Document createInput(final String river, final double from, final double to, final Integer startYear, final Integer endYear) {
+    public static final Document createInput(final String river, final double from, final double to, final java.util.Date startDate,
+            final java.util.Date endDate) {
 
         final Document input = XMLUtils.newDocument();
 
@@ -87,16 +88,15 @@
         endEl.setTextContent(Double.valueOf(to).toString());
         mainvalues.appendChild(endEl);
 
-        if (startYear != null) {
-            final Element startYearElement = ec.create("startYear");
-            startYearElement.setTextContent(Integer.toString(startYear));
-            mainvalues.appendChild(startYearElement);
+        if (startDate != null) { // IMPORTANT, MainValueService and DynamicMainValueService share this method. MainvalueService does not have Dates
+            final Element startDateElement = ec.create("startDate");
+            startDateElement.setTextContent(String.valueOf(startDate.getTime()));
+            mainvalues.appendChild(startDateElement);
         }
-
-        if (endYear != null) {
-            final Element endYearElement = ec.create("endYear");
-            endYearElement.setTextContent(Integer.toString(endYear));
-            mainvalues.appendChild(endYearElement);
+        if (endDate != null) {// IMPORTANT, MainValueService and DynamicMainValueService share this method. MainvalueService does not have Dates
+            final Element endDateElement = ec.create("endDate");
+            endDateElement.setTextContent(String.valueOf(endDate.getTime()));
+            mainvalues.appendChild(endDateElement);
         }
 
         input.appendChild(mainvalues);
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesServiceImpl.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesServiceImpl.java	Wed Aug 15 13:59:09 2018 +0200
@@ -8,6 +8,8 @@
 
 package org.dive4elements.river.client.server;
 
+import java.util.Date;
+
 import org.dive4elements.river.client.client.services.DynamicMainValuesService;
 import org.dive4elements.river.client.shared.exceptions.ServerException;
 import org.dive4elements.river.client.shared.model.WQInfoObject;
@@ -20,10 +22,10 @@
     private static final long serialVersionUID = 1L;
 
     @Override
-    public WQInfoObject[] getWQInfo(final String locale, final String river, final double from, final double to, final int startYear, final int endYear)
+    public WQInfoObject[] getWQInfo(final String locale, final String river, final double from, final double to, final Date startDate, final Date endDate)
             throws ServerException {
 
-        final Document input = createInput(river, from, to, startYear, endYear);
+        final Document input = createInput(river, from, to, startDate, endDate);
 
         return callService("dynamicMainvalues", input, locale);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesTimeRangeDeterminationServiceImpl.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,142 @@
+/* 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.server;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException;
+import org.dive4elements.artifacts.httpclient.http.HttpClient;
+import org.dive4elements.artifacts.httpclient.http.HttpClientImpl;
+import org.dive4elements.river.client.client.services.DynamicMainValuesTimeRangeDeterminationService;
+import org.dive4elements.river.client.shared.exceptions.ServerException;
+import org.dive4elements.river.client.shared.model.GaugeInfoObject;
+import org.dive4elements.river.client.shared.model.GaugeInfoObjectImpl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DynamicMainValuesTimeRangeDeterminationServiceImpl extends RemoteServiceServlet implements DynamicMainValuesTimeRangeDeterminationService {
+    private static final long serialVersionUID = 1L;
+
+    private static final String XPATH_ROOT = "dynamic-mainvalues-input";
+    private String globalErrorMsg = null;
+
+    private GaugeInfoObject[] callService(final String serviceName, final Document input, final String locale) throws ServerException {
+        final String url = getServletContext().getInitParameter("server-url");
+
+        final HttpClient client = new HttpClientImpl(url, locale);
+
+        try {
+            final Document result = client.callService(url, serviceName, input);
+            final GaugeInfoObject[] objects = extractDates(result);
+            if (!this.globalErrorMsg.equals(""))
+                throw new ServerException(this.globalErrorMsg);
+            // log.debug("Extract wq info objects now.");
+            return objects;
+
+        }
+        catch (final ConnectionException ce) {
+            // log.error(ce, ce);
+        }
+
+        throw new ServerException("error_no_wqinput_found");
+    }
+
+    private GaugeInfoObject[] extractDates(final Document result) throws ServerException {
+        final List<GaugeInfoObject> results = new ArrayList<GaugeInfoObject>();
+        final NodeList list = result.getChildNodes();
+
+        if (list != null && list.getLength() == 1) {
+            // log.warn("No wq info found.");
+            final Node nodes = list.item(0);
+            final NodeList childNodes = nodes.getChildNodes();
+            for (int i = 0; i < childNodes.getLength(); i++) {
+                final Node node = childNodes.item(i);
+                if (node.getLocalName().equals("global-error-msg")) {
+                    this.globalErrorMsg = node.getTextContent();
+                } else { // name equals gauge
+
+                    final NamedNodeMap map = node.getAttributes();
+                    final String gaugeName = getStringFromMap("name", map);
+                    final String error = getStringFromMap("error-message", map);
+                    final GaugeInfoObject gi = new GaugeInfoObjectImpl(gaugeName, error, getDateFromMap("date-from", map), getDateFromMap("date-to", map));
+                    results.add(gi);
+                }
+            }
+
+        }
+        return results.toArray(new GaugeInfoObject[results.size()]);
+    }
+
+    private Date getDateFromMap(final String attrName, final NamedNodeMap map) {
+        final Node dateNode = map.getNamedItem(attrName);
+        if (dateNode != null)
+            return new Date(Long.parseLong(dateNode.getNodeValue())); // errorHandling? Dürfte eigentlich keine Parse-Probleme bekommen!
+        return null;
+    }
+
+    private String getStringFromMap(final String attrName, final NamedNodeMap map) {
+        final Node node = map.getNamedItem(attrName);
+        if (node != null)
+            return node.getNodeValue();
+        return null;
+    }
+
+    @Override
+    public GaugeInfoObject[] getGaugeInfo(final String locale, final String river, final String[] gauges, final int startYear, final int endYear)
+            throws ServerException {
+
+        final Document input = createInput(river, gauges, startYear, endYear);
+
+        return callService("dynamicMainvaluesTimeRangeDetermination", input, locale);
+
+    }
+
+    public static final Document createInput(final String river, final String[] gauges, final int startYear, final int endYear) {
+
+        final Document input = XMLUtils.newDocument();
+
+        final XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(input, ArtifactNamespaceContext.NAMESPACE_URI,
+                ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        final Element inputElement = ec.create("dynamic-mainvalues-input");
+
+        final Element riverEl = ec.create("river");
+        riverEl.setTextContent(river);
+        inputElement.appendChild(riverEl);
+
+        for (final String gauge : gauges) {
+            final Element gaugeEl = ec.create("gauge");
+            gaugeEl.setTextContent(gauge);
+            inputElement.appendChild(gaugeEl);
+        }
+
+        final Element startYearElement = ec.create("startYear");
+        startYearElement.setTextContent(String.valueOf(startYear));
+        inputElement.appendChild(startYearElement);
+
+        final Element endYearElement = ec.create("endYear");
+        endYearElement.setTextContent(String.valueOf(endYear));
+        inputElement.appendChild(endYearElement);
+
+        input.appendChild(inputElement);
+
+        return input;
+    }
+
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DischargeInfoObjectImpl.java	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DischargeInfoObjectImpl.java	Wed Aug 15 13:59:09 2018 +0200
@@ -8,12 +8,13 @@
 
 package org.dive4elements.river.client.shared.model;
 
-
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class DischargeInfoObjectImpl implements DischargeInfoObject {
 
+    private static final long serialVersionUID = 1L;
+
     protected String description;
 
     protected Integer startYear;
@@ -22,43 +23,34 @@
 
     protected String bfgId;
 
-
     public DischargeInfoObjectImpl() {
     }
 
-
-    public DischargeInfoObjectImpl(
-        String description,
-        Integer startYear,
-        Integer endYear,
-        String bfgId
-    ) {
+    public DischargeInfoObjectImpl(final String description, final Integer startYear, final Integer endYear, final String bfgId) {
         this.description = description;
-        this.startYear   = startYear;
-        this.endYear     = endYear;
-        this.bfgId       = bfgId;
+        this.startYear = startYear;
+        this.endYear = endYear;
+        this.bfgId = bfgId;
     }
 
     @Override
     public String getDescription() {
-        return description;
+        return this.description;
     }
 
-
     @Override
     public Integer getStartYear() {
-        return startYear;
+        return this.startYear;
     }
 
-
     @Override
     public Integer getEndYear() {
-        return endYear;
+        return this.endYear;
     }
 
     @Override
     public String getBfGId() {
-        return bfgId;
+        return this.bfgId;
     }
 }
 // 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/shared/model/GaugeInfoObject.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,27 @@
+/* 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.shared.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface GaugeInfoObject extends Serializable {
+
+    String getName();
+
+    String getErrorMessage();
+
+    Date getStartTime();
+
+    Date getStopTime();
+}
+// 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/shared/model/GaugeInfoObjectImpl.java	Wed Aug 15 13:59:09 2018 +0200
@@ -0,0 +1,59 @@
+/* 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.shared.model;
+
+import java.util.Date;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class GaugeInfoObjectImpl implements GaugeInfoObject {
+
+    private static final long serialVersionUID = 1L;
+
+    protected String name;
+
+    protected String errorMsg;
+
+    Date startTime;
+
+    Date stopTime;
+
+    public GaugeInfoObjectImpl() {
+    }
+
+    public GaugeInfoObjectImpl(final String name, final String errorMsg, final Date startTime, final Date stopTime) {
+        this.name = name;
+        this.errorMsg = errorMsg;
+        this.startTime = startTime;
+        this.stopTime = stopTime;
+    }
+
+    @Override
+    public Date getStopTime() {
+        return this.stopTime;
+    }
+
+    @Override
+    public Date getStartTime() {
+        return this.startTime;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String getErrorMessage() {
+        return this.errorMsg;
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/gwt-client/src/main/webapp/WEB-INF/features.xml	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/webapp/WEB-INF/features.xml	Wed Aug 15 13:59:09 2018 +0200
@@ -9,7 +9,9 @@
     <ftr:feature>module:new_map</ftr:feature>
     <ftr:feature>module:new_chart</ftr:feature>
     <ftr:feature>module:fixanalysis</ftr:feature>
-    <ftr:feature>river:Beispielfluss</ftr:feature> 
+    <ftr:feature>river:Beispielfluss</ftr:feature>
+    <ftr:feature>river:Elbe</ftr:feature>
+    <ftr:feature>river:Rhein</ftr:feature>
   </ftr:role>
   <ftr:role name="d4e_demo_extern">
     <ftr:feature>module:winfo</ftr:feature>
--- a/gwt-client/src/main/webapp/WEB-INF/web.xml	Wed Aug 15 13:22:00 2018 +0200
+++ b/gwt-client/src/main/webapp/WEB-INF/web.xml	Wed Aug 15 13:59:09 2018 +0200
@@ -208,6 +208,11 @@
     <servlet-name>dynamicMainvalues</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DynamicMainValuesServiceImpl</servlet-class>
   </servlet>
+  
+  <servlet>
+    <servlet-name>dynamicMainvaluesTimeRangeDetermination</servlet-name>
+    <servlet-class>org.dive4elements.river.client.server.DynamicMainValuesTimeRangeDeterminationServiceImpl</servlet-class>
+  </servlet>
 
   <servlet>
     <servlet-name>gaugeinfo</servlet-name>
@@ -494,6 +499,11 @@
   </servlet-mapping>
 
   <servlet-mapping>
+    <servlet-name>dynamicMainvaluesTimeRangeDetermination</servlet-name>
+    <url-pattern>/flys/dynamic-mainvalues-timerange-determination</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
     <servlet-name>gaugeinfo</servlet-name>
     <url-pattern>/flys/gaugeinfo</url-pattern>
   </servlet-mapping>

http://dive4elements.wald.intevation.org