changeset 6503:9daf7c9cf663 double-precision

merged changes from default into double-precision branch
author Tom Gottfried <tom.gottfried@intevation.de>
date Fri, 28 Jun 2013 16:59:07 +0200
parents 3b93f439e954 (current diff) 7cb247824ed1 (diff)
children 128ab9169db1
files
diffstat 38 files changed, 667 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Jun 28 16:58:46 2013 +0200
+++ b/.hgtags	Fri Jun 28 16:59:07 2013 +0200
@@ -53,3 +53,4 @@
 b689d2b9d1675739778083b2bcba336abb33f70c 3.0.6
 5733d7f27196c5a8cf18231fbf187738f8fea560 3.0.7
 eec895f6ec801a7faaed96e9f01721e1143e7bb8 3.0.8
+41152c3a532d63a25e9fa348ca4286bdd76069ef 3.0.9
--- a/artifacts/doc/conf/artifacts/fixanalysis.xml	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/doc/conf/artifacts/fixanalysis.xml	Fri Jun 28 16:59:07 2013 +0200
@@ -269,14 +269,14 @@
                     	<facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/>
                         <facet name="w_differences" description="facet.w_differences"/>
                         <facet name="other.wkms" description="facet.other.wkms"/>
+                        <facet name="other.wq"               description="WQ-Type of data" />
                         <facet name="other.wqkms" description="facet.other.wqkms"/>
                         <facet name="other.wqkms.q"          description="W-Type of data" />
                         <facet name="other.wqkms.w"          description="W-Type of data" />
                         <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/>
-                        <facet name="w_differences.manualpoints" description="Manuelle Punkte"/>
-                        <facet name="longitudinal_section.manualpoints" description="Manuelle Punkte"/>
                         <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
                         <facet name="longitudinal_section.area" description="facet.longitudinal_section.area"/>
+                        <facet name="longitudinal_section.manualpoints" description="Manuelle Punkte"/>
                     </facets>
                 </outputmode>
                 <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mine-type="image/png" type="chart">
@@ -286,8 +286,8 @@
                         <facet name="fix_sector_average_wq_2" description="Average values for Ws in Q sectors."/>
                         <facet name="fix_sector_average_wq_3" description="Average values for Ws in Q sectors."/>
                         <facet name="fix_analysis_events_wq" description="Raw event values used in the calculation"/>
-                        <facet name="fix_reference_events_wq" description="Raw event values used in the calculation"/>
                         <facet name="fix_wq_curve" description="WQ curve"/>
+                        <facet name="fix_wq_ls" description="WQ LS curve"/>
                         <facet name="fix_outlier" description="The outliers"/>
                         <facet name="qsectors" description="qsectors."/>
                         <facet name="fix_events_wqkms"          description="WQKMS-Type of data" />
@@ -295,7 +295,7 @@
                         <facet name="other.wqkms.w"          description="W-Type of data" />
                         <facet name="other.wkms" description="facet.other.wqkms"/>
                         <facet name="other.wqkms" description="facet.other.wqkms"/>
-                        <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/>
+                        <!--issue1383: facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/-->
                         <facet name="other.wq"    description="Point-like data like fixations"/>
                         <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/>
                         <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/>
--- a/artifacts/doc/conf/conf.xml	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/doc/conf/conf.xml	Fri Jun 28 16:59:07 2013 +0200
@@ -144,6 +144,10 @@
 
         <service-factories>
             <service-factory
+                name="server-info"
+                service="org.dive4elements.river.artifacts.services.ServerInfoService"
+                description="This service provides generic information and configuration of the artifact server.">org.dive4elements.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
                 name="rivers"
                 service="org.dive4elements.river.artifacts.services.RiverService"
                 description="This service returns a list of provided rivers by the artifact server.">org.dive4elements.artifactdatabase.DefaultServiceFactory</service-factory>
--- a/artifacts/doc/conf/meta-data.xml	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/doc/conf/meta-data.xml	Fri Jun 28 16:59:07 2013 +0200
@@ -50,6 +50,7 @@
                   </dc:when>
                   <dc:when test="$out = 'discharge_longitudinal_section'">
                     <dc:call-macro name="annotations"/>
+                    <dc:call-macro name="officiallines_user"/>
                   </dc:when>
                   <dc:when test="$out = 'historical_discharge_wq'">
                     <dc:call-macro name="mainvalues"/>
@@ -57,6 +58,7 @@
                   <dc:when test="$out = 'cross_section'">
                     <dc:call-macro name="cross_sections"/>
                     <dc:call-macro name="hyks"/>
+                    <dc:call-macro name="officiallines_user"/>
                   </dc:when>
                   <dc:when test="$out = 'discharge_curve'">
                     <dc:call-macro name="mainvalues"/>
@@ -78,6 +80,7 @@
                   </dc:when>
                   <dc:when test="$out = 'longitudinal_section'">
                     <dc:call-macro name="annotations"/>
+                    <dc:call-macro name="officiallines_user"/>
                   </dc:when>
                   <dc:when test="$out = 'fix_longitudinal_section_curve'">
                     <dc:call-macro name="annotations"/>
@@ -2322,19 +2325,15 @@
         <dc:container-context container="official-lines">
           <dc:properties>
             <dc:property name="name" alias="olname"/>
-            <dc:property name="wst" alias="wstid"/>
+            <dc:property name="wstId" alias="wstid"/>
             <dc:property name="columnPos" alias="wstcolpos"/>
           </dc:properties>
           <dc:if test="dc:has-result()">
             <officiallines>
               <dc:for-each>
-                <dc:element name="${olname}">
-                  <dc:attribute name="name" value="${olname}"/>
-                  <dc:attribute name="ids" value="additionals-wstv-${wstcolpos}-${wstid}"/>
-                  <dc:attribute name="factory" value="staticwkms"/>
-                  <dc:attribute name="target_out" value="${out}"/>
-                  <dc:attribute name="out" value="${out}"/>
-                </dc:element>
+                <column name="{$olname}"
+                      ids="additionals-wstv-{$wstcolpos}-{$wstid}"
+                      factory="staticwqkms" target_out="{$out}"/>
               </dc:for-each>
             </officiallines>
           </dc:if>
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/FixationArtifact.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/FixationArtifact.java	Fri Jun 28 16:59:07 2013 +0200
@@ -56,6 +56,7 @@
         return ARTIFACT_NAME;
     }
 
+    /** Calculate waterlines against a cross section. */
     @Override
     public Lines.LineData getWaterLines(
         int                  facetIdx,
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri Jun 28 16:59:07 2013 +0200
@@ -278,7 +278,7 @@
 
             String [] columnNames = new String[properties.length];
             for (int i = 0; i < columnNames.length; ++i) {
-                columnNames[i] = properties[i][1];
+                columnNames[i] = properties[i][1].toUpperCase();
             }
 
             ResultData rd = new ResultData(columnNames);
@@ -825,12 +825,12 @@
         throws SQLException
         {
             log.debug("dc:message");
-            if (log.isInfoEnabled()) {
+            if (log.isDebugEnabled()) {
                 String value = current.getTextContent();
                 if (value.indexOf('{') >= 0) { // Performance tweak
                     value = expandXPathValue(value);
                 }
-                log.info("MESSAGE: " + value);
+                log.debug("MESSAGE: " + value);
             }
         }
 
@@ -1124,7 +1124,8 @@
                     }
                     else if ("macro".equals(localName)
                          ||  "comment".equals(localName)
-                         ||  "statement".equals(localName)) {
+                         ||  "statement".equals(localName)
+                         ||  "properties".equals(localName)) {
                         // Simply ignore them.
                     }
                     else if ("element".equals(localName)) {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/FunctionResolver.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/FunctionResolver.java	Fri Jun 28 16:59:07 2013 +0200
@@ -234,7 +234,8 @@
         Object locations = args.get(1);
         Object from      = args.get(2);
 
-        if (mode instanceof String && mode.equals("location")) {
+        if ((mode instanceof String && mode.equals("location")) || 
+            (locations instanceof String && !((String)locations).isEmpty())) {
             if (!(locations instanceof String)) {
                 return -FAR_AWAY;
             }
@@ -279,7 +280,8 @@
         Object locations = args.get(1);
         Object to        = args.get(2);
 
-        if (mode instanceof String && mode.equals("location")) {
+        if ((mode instanceof String && mode.equals("location")) ||
+            (locations instanceof String && !((String)locations).isEmpty())) {
             if (!(locations instanceof String)) {
                 return FAR_AWAY;
             }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Fri Jun 28 16:59:07 2013 +0200
@@ -373,6 +373,7 @@
     String FIX_SECTOR_AVERAGE_LS_DEVIATION = "fix_sector_average_ls_deviation";
 
     String FIX_WQ_CURVE = "fix_wq_curve";
+    String FIX_WQ_LS = "fix_wq_ls";
     String FIX_OUTLIER = "fix_outlier";
 
     String FIX_ANALYSIS_PERIODS_DWT = "fix_analysis_periods_dwt";
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java	Fri Jun 28 16:59:07 2013 +0200
@@ -17,6 +17,7 @@
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.Element;
 
+import org.apache.log4j.Logger;
 import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.cache.CacheFactory;
 import org.dive4elements.river.model.Gauge;
@@ -31,6 +32,8 @@
 {
     public static final String CACHE_NAME = "official-lines";
 
+    private static Logger log = Logger.getLogger(OfficialLineFinder.class);
+
     // We will only have one entry in this cache.
     public static final String CACHE_KEY = CACHE_NAME;
 
@@ -87,6 +90,14 @@
             ValueRange r = (ValueRange)o;
             return wstId == r.wstId && columnPos == r.columnPos;
         }
+
+        @Override
+        public String toString() {
+            return "[" + name +
+                " value: " + value +
+                " wstId: " + wstId +
+                " pos: " + columnPos + "]";
+        }
     }
 
     public OfficialLineFinder() {
@@ -115,14 +126,16 @@
 
     public static Map<String, List<ValueRange>> getAllUncached() {
 
+        boolean debug = log.isDebugEnabled();
+
         Map<String, List<ValueRange>> rivers2officialLines =
             new HashMap<String, List<ValueRange>>();
 
-
         for (OfficialLine line: OfficialLine.fetchAllOfficalLines()) {
-            String   name = line.getNamedMainValue().getName();
-            WstColumn wc  = line.getWstColumn();
-            Wst       wst = wc.getWst();
+            NamedMainValue nmv = line.getNamedMainValue();
+            Integer   mnvId    = nmv.getId();
+            WstColumn wc       = line.getWstColumn();
+            Wst       wst      = wc.getWst();
 
             List<ValueRange> ranges = new ArrayList<ValueRange>();
 
@@ -131,17 +144,24 @@
             for (Gauge gauge: gauges) {
                 List<MainValue> mainValues = gauge.getMainValues();
                 for (MainValue mainValue: mainValues) {
-                    NamedMainValue nmv = mainValue.getMainValue();
-                    if (nmv.getName().equalsIgnoreCase(name)) {
+                    NamedMainValue tnmv = mainValue.getMainValue();
+                    if (tnmv.getId().equals(mnvId)) {
                         // found gauge with this main value
 
-                        double from = gauge.getRange().getA().doubleValue();
-                        double to   = gauge.getRange().getA().doubleValue();
+                        double from  = gauge.getRange().getA().doubleValue();
+                        double to    = gauge.getRange().getA().doubleValue();
                         double value = mainValue.getValue().doubleValue();
                         int    wstId = wst.getId();
                         int    pos   = wc.getPosition();
-                        ValueRange range =
-                            new ValueRange(from, to, value, wstId, pos, name);
+                        ValueRange range = new ValueRange(
+                            from, to, value, wstId, pos, nmv.getName());
+
+                        if (debug) {
+                            log.debug(
+                                "river: " + river.getName() +
+                                " gauge: " + gauge.getName() +
+                                " ol: " + range);
+                        }
                         ranges.add(range);
                         break;
                     }
@@ -149,7 +169,14 @@
             }
 
             if (!ranges.isEmpty()) {
-                rivers2officialLines.put(river.getName(), ranges);
+                String rname = river.getName();
+                List<ValueRange> old = rivers2officialLines.get(rname);
+                if (old != null) {
+                    old.addAll(ranges);
+                }
+                else {
+                    rivers2officialLines.put(rname, ranges);
+                }
             }
         }
 
@@ -163,11 +190,19 @@
     }
 
     public static Range extractRange(D4EArtifact artifact) {
+
         String mode      = nn(artifact.getDataAsString("ld_mode"));
         String locations = nn(artifact.getDataAsString("ld_locations"));
         String from      = nn(artifact.getDataAsString("ld_from"));
         String to        = nn(artifact.getDataAsString("ld_to"));
 
+        if (log.isDebugEnabled()) {
+            log.debug("ld_mode: '" + mode + "'");
+            log.debug("ld_locations: '" + locations + "'");
+            log.debug("ld_from: '" + from + "'");
+            log.debug("ld_to: '" + to + "'");
+        }
+
         if (mode.equals("location")) {
             try {
                 String loc = locations.replace(" ", "");
@@ -309,9 +344,18 @@
         if (ranges == null) {
             return Collections.<ValueRange>emptyList();
         }
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("Before range filter:" + ranges);
+        }
 
         ranges = filterByRange(extractRange(artifact), ranges);
 
+        if (debug) {
+            log.debug("After range filter:" + ranges);
+        }
+
         if (ranges.isEmpty()) {
             return Collections.<ValueRange>emptyList();
         }
@@ -324,6 +368,16 @@
             qRange = tripleQRange(artifact);
         }
 
-        return filterByQRange(qRange, ranges);
+        if (debug) {
+            log.debug("Q range filter: " + qRange);
+        }
+
+        ranges = filterByQRange(qRange, ranges);
+
+        if (debug) {
+            log.debug("After q range filter: " + ranges);
+        }
+
+        return ranges;
     }
 }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/Range.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/Range.java	Fri Jun 28 16:59:07 2013 +0200
@@ -111,5 +111,9 @@
     public Object clone() {
         return new Range(this.start, this.end);
     }
+
+    public String toString() {
+        return "[Range: start=" + start + " end=" + end + "]";
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WaterlevelFacet.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WaterlevelFacet.java	Fri Jun 28 16:59:07 2013 +0200
@@ -37,6 +37,8 @@
         String      stateID,
         String      hash
     ) {
+        // Pretty weird to change order of the two String params
+        // hash and stateID in comparison to parent. Its difficult to fix, now.
         super(index, name, description, type, hash, stateID);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixWaterlevelFacet.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixWaterlevelFacet.java	Fri Jun 28 16:59:07 2013 +0200
@@ -32,10 +32,12 @@
         String      name,
         String      description,
         ComputeType type,
-        String      stateID,
-        String      hash
+        String      hash,
+        String      stateID
     ) {
-        super(index, name, description, type, hash, stateID);
+        // Note that in super, hash and stateID are on switched positions.
+        // on super.super it is this way around again.
+        super(index, name, description, type, stateID, hash);
     }
 
     @Override
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadCalculation.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadCalculation.java	Fri Jun 28 16:59:07 2013 +0200
@@ -11,6 +11,7 @@
 import gnu.trove.TDoubleArrayList;
 
 import java.util.ArrayList;
+import java.util.TreeSet;
 import java.util.List;
 
 import org.apache.log4j.Logger;
@@ -345,7 +346,9 @@
         Range lastSuspRange = null;
         double lastSuspValue = 0d;
 
-        for (double km: load.getKms()) {
+        TreeSet<Double> kms = new TreeSet<Double>(load.getKms());
+
+        for (double km: kms) {
             logger.debug ("Trying to add at km " + km);
             SedimentLoadFraction fraction = load.getFraction(km);
             if (complete(fraction)) {
@@ -446,7 +449,7 @@
                         lastSuspRange = null;
                         lastOtherValue = total - lastSuspValue;
                     }
-                    if (Math.abs(lastSuspRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) {
+                    if (lastSuspRange != null && Math.abs(lastSuspRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) {
                         lastOtherRange = null;
                         lastSuspRange = null;
                     }
@@ -462,6 +465,20 @@
             else {
                 // Some values are missing or no intersection with former values.
                 // Stay as we are.
+                if (hasButSuspValues(fraction)) {
+                    double total = fraction.getCoarse() +
+                        fraction.getFineMiddle() +
+                        fraction.getSand() +
+                        fraction.getSuspSand();
+                    lastOtherRange = fraction.getCoarseRange();
+                    lastOtherValue = total;
+                    lastSuspRange = null;
+                }
+                else if (hasOnlySuspValues(fraction)) {
+                    lastSuspRange = fraction.getSuspSedimentRange();
+                    lastSuspValue = fraction.getSuspSediment();
+                    lastOtherRange = null;
+                }
             }
         }
         return fairLoad;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java	Fri Jun 28 16:59:07 2013 +0200
@@ -55,7 +55,7 @@
     public static final String SQL_SELECT_EPOCHS =
         "SELECT DISTINCT " +
         "       sy.description AS description, " +
-        "       ti.start_time AS start, " +
+        "       ti.start_time AS startYear, " +
         "       ti.stop_time AS end, " +
         "       u.name AS unit" +
         "   FROM     sediment_yield sy " +
@@ -90,7 +90,7 @@
     public static final String SQL_SELECT_UNKNOWN_DATA =
         "SELECT" +
         "       sy.description AS description, " +
-        "       ti.start_time AS start, " +
+        "       ti.start_time AS startYear, " +
         "       ti.stop_time AS end, " +
         "       syv.value AS load, " +
         "       syv.station AS km, " +
@@ -109,7 +109,7 @@
     public static final String SQL_SELECT_UNKNOWN =
         "SELECT DISTINCT " +
         "    sy.description AS description, " +
-        "    ti.start_time AS start, " +
+        "    ti.start_time AS startYear, " +
         "    ti.stop_time AS end " +
         "FROM sediment_yield sy " +
         "    JOIN rivers r ON sy.river_id = r.id " +
@@ -268,7 +268,7 @@
         else if (type.equals("epoch")) {
             sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCHS)
                 .addScalar("description", StandardBasicTypes.STRING)
-                .addScalar("start", StandardBasicTypes.DATE)
+                .addScalar("startYear", StandardBasicTypes.DATE)
                 .addScalar("end", StandardBasicTypes.DATE);
             sqlQuery.setString("name", river);
             sqlQuery.setDouble("startKm", startKm);
@@ -520,7 +520,7 @@
 
         sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN_DATA)
             .addScalar("description", StandardBasicTypes.STRING)
-            .addScalar("start", StandardBasicTypes.DATE)
+            .addScalar("startYear", StandardBasicTypes.DATE)
             .addScalar("end", StandardBasicTypes.DATE)
             .addScalar("load", StandardBasicTypes.DOUBLE)
             .addScalar("km", StandardBasicTypes.DOUBLE)
@@ -553,7 +553,7 @@
         Session session = SessionHolder.HOLDER.get();
         SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN)
             .addScalar("description", StandardBasicTypes.STRING)
-            .addScalar("start", StandardBasicTypes.DATE)
+            .addScalar("startYear", StandardBasicTypes.DATE)
             .addScalar("end", StandardBasicTypes.DATE);
         sqlQuery.setString("river", river);
         List<Object[]> results = sqlQuery.list();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java	Fri Jun 28 16:59:07 2013 +0200
@@ -206,7 +206,7 @@
         doc.appendChild(rootEl);
 
         appendMetaInformation(doc, rootEl, river, gauge, context);
-        appendMainValues(doc, rootEl, mainValues, river.getName(), context);
+        appendMainValues(doc, rootEl, mainValues, river.getId(), context);
 
         return doc;
     }
@@ -252,9 +252,9 @@
 
 
     /** Checks i a main value has an official associated, */
-    protected static boolean hasOfficialLine(NamedMainValue nmv, String river) {
+    protected static boolean hasOfficialLine(NamedMainValue nmv, Integer riverId) {
         for (OfficialLine ol: nmv.getOfficialLines()) {
-            if (river.equals(ol.getWstColumn().getWst().getRiver().getName())) {
+            if (ol.getWstColumn().getWst().getRiver().getId().equals(riverId)) {
                 return true;
             }
         }
@@ -266,7 +266,7 @@
         Document        doc,
         Element         root,
         List<MainValue> mainValues,
-        String          river,
+        Integer         riverId,
         Object          context)
     {
         logger.debug("MainValuesService.appendMainValues");
@@ -279,7 +279,7 @@
         Element list = cr.create("mainvalues");
 
         for (MainValue mainValue: mainValues) {
-            Element newEl = buildMainValueElement(doc, mainValue, river, context);
+            Element newEl = buildMainValueElement(doc, mainValue, riverId, context);
 
             if (newEl != null) {
                 list.appendChild(newEl);
@@ -303,7 +303,7 @@
     protected Element buildMainValueElement(
         Document  doc,
         MainValue mainValue,
-        String    river,
+        Integer   riverId,
         Object    context)
     {
         ElementCreator cr = new ElementCreator(
@@ -320,7 +320,7 @@
         cr.addAttr(el, "name", namedMainValue.getName());
         cr.addAttr(el, "type", mainValueType.getName());
 
-        if (hasOfficialLine(namedMainValue, river)) {
+        if (hasOfficialLine(namedMainValue, riverId)) {
             cr.addAttr(el, "official", "true");
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/ServerInfoService.java	Fri Jun 28 16:59:07 2013 +0200
@@ -0,0 +1,57 @@
+package org.dive4elements.river.artifacts.services;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.GlobalContext;
+import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
+import org.dive4elements.artifacts.common.utils.Config;
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Through this service the client can retrieve basic information about or
+ * configuration of the artifact server.
+ * Currently it only returns the help-url (wiki) to the client.
+ *
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class ServerInfoService extends D4EService {
+
+    /** The logger used in this service.*/
+    private static Logger logger = Logger.getLogger(ServerInfoService.class);
+
+    private static final String XPATH_HELP_URL = "/artifact-database/help-url/text()";
+
+    @Override
+    protected Document doProcess(Document data, GlobalContext globalContext,
+            CallMeta callMeta) {
+        logger.debug("ServerInfoService.process");
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element serverInfo = ec.create("server");
+
+        String helpUrl = (String) XMLUtils.xpath(
+                Config.getConfig(),
+                XPATH_HELP_URL,
+                XPathConstants.STRING);
+
+        Element info = ec.create("info");
+        ec.addAttr(info, "key", "help-url", true);
+        ec.addAttr(info, "value", helpUrl, true);
+        serverInfo.appendChild(info);
+
+        result.appendChild(serverInfo);
+
+        return result;
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelState.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelState.java	Fri Jun 28 16:59:07 2013 +0200
@@ -17,14 +17,17 @@
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.WINFOArtifact;
+import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.CrossSectionWaterLineFacet;
 import org.dive4elements.river.artifacts.model.DataFacet;
 import org.dive4elements.river.artifacts.model.EmptyFacet;
 import org.dive4elements.river.artifacts.model.FacetTypes;
+import org.dive4elements.river.artifacts.model.OfficialLineFinder;
 import org.dive4elements.river.artifacts.model.ReportFacet;
 import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.artifacts.model.WaterlevelFacet;
+import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.utils.RiverUtils;
 
 /** State in which a waterlevel has been calculated. */
@@ -112,7 +115,22 @@
             facets.add(pdf);
         }
 
-        if (res.getReport().hasProblems()) {
+        Calculation report = res.getReport();
+
+        List<OfficialLineFinder.ValueRange> ols =
+            OfficialLineFinder.findOfficialLines(winfo);
+
+        if (!ols.isEmpty()) {
+            for (OfficialLineFinder.ValueRange ol: ols) {
+                report.addProblem(Resources.format(
+                    cc.getMeta(),
+                    "official.line.found",
+                    "Found official line for {0}.",
+                    ol.getName()));
+            }
+        }
+
+        if (report.hasProblems()) {
             facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id));
         }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/fixation/FixRealizingCompute.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/fixation/FixRealizingCompute.java	Fri Jun 28 16:59:07 2013 +0200
@@ -108,13 +108,17 @@
                 nameQ = "Q(" + nameW + ")";
             }
 
+            Facet wq = new FixWaterlevelFacet(
+                i, FIX_WQ_LS, nameW, ComputeType.ADVANCE, hash, id);
+
             Facet w = new FixWaterlevelFacet(
-                i, LONGITUDINAL_W, nameW);
+                i, LONGITUDINAL_W, nameW, ComputeType.ADVANCE, hash, id);
 
             Facet q = new FixWaterlevelFacet(
-                i, LONGITUDINAL_Q, nameQ);
+                i, LONGITUDINAL_Q, nameQ, ComputeType.ADVANCE, hash, id);
             Facet csFacet = new CrossSectionWaterLineFacet(i, nameW);
 
+            facets.add(wq);
             facets.add(w);
             facets.add(q);
             facets.add(csFacet);
@@ -157,12 +161,6 @@
             Resources.getMsg(meta, I18N_WQ_CURVE, I18N_WQ_CURVE) + " ("
                 + access.getFunction() + ")"));
 
-        facets.add(new FixReferenceEventsFacet(
-            0,
-            FIX_REFERENCE_EVENTS_WQ,
-            Resources.getMsg(meta, I18N_WQ_EVENTS, I18N_WQ_EVENTS)));
-
-
         if (access.getPreprocessing()) {
             facets.add(new FixOutlierFacet(
                 0,
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveGenerator.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveGenerator.java	Fri Jun 28 16:59:07 2013 +0200
@@ -62,8 +62,6 @@
 
     public static final String I18N_CHART_TITLE_DEFAULT = "Abflusskurve";
     public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]";
-    public static final String I18N_MAINVALUES_Q_LABEL = "Q (Haupt- und Extremwerte)";
-    public static final String I18N_MAINVALUES_W_LABEL = "W (Haupt- und Extremwerte)";
 
     protected NumberAxis firstYAxis;
 
@@ -92,34 +90,25 @@
     }
 
 
-    /**
-     * Returns the PNP (Datum) of gauge, if at gauge, 0 otherwise.
-     */
-    protected int getCurrentGaugeDatum() {
-        // Code borrowed from FixATWriter.
-        Gauge gauge = RiverUtils.getGauge((D4EArtifact) getMaster());
-        int subtractPNP = 0;
-        if (Math.abs(getRange()[0] - gauge.getStation().doubleValue()) < 1e-4) {
-            subtractPNP = (int) Math.round(gauge.getDatum().doubleValue() /** 100*/);
-        }
-        return subtractPNP;
-    }
-
 
     @Override
     protected String getDefaultYAxisLabel(int pos) {
         D4EArtifact flys = (D4EArtifact) master;
 
         String unit = RiverUtils.getRiver(flys).getWstUnit().getName();
+        if (pos == 0 && getCurrentGaugeDatum() != 0)
+            unit = "cm";
 
         return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT, new Object[] { unit });
     }
 
 
     /**
-     * Create Y (range) axis for given index.
-     * Shall be overriden by subclasses.
+     * Create Y (range) axis for given index, here with a special axis
+     * that depends on other axis (does translation and scaling for
+     * special case at gauge in cm).
      */
+    @Override
     protected NumberAxis createYAxis(int index) {
         if (index == 0) {
             firstYAxis = super.createYAxis(0);
@@ -184,8 +173,11 @@
                 || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W)
                 || name.equals(MAINVALUES_W)
         ) {
-            doAnnotations((RiverAnnotation)
-                artifactFacet.getData(context), artifactFacet, attr, visible);
+            RiverAnnotation mainValues = (RiverAnnotation) artifactFacet.getData(context);
+            translateRiverAnnotation(mainValues);
+            doAnnotations(
+                mainValues,
+                artifactFacet, attr, visible);
         }
         else if (name.equals(STATIC_WKMS_INTERPOL) || name.equals(HEIGHTMARKS_POINTS)) {
             doWAnnotations(
@@ -255,9 +247,9 @@
         logger.debug("ComputedDischargeCurveGenerator: doDischargeQOut");
         XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
 
-        int subtractPNP = getCurrentGaugeDatum();
+        double subtractPNP = getCurrentGaugeDatum();
 
-        if (subtractPNP == 0) {
+        if (subtractPNP == 0d) {
             StyledSeriesBuilder.addPointsQW(series, wqkms);
             addAxisSeries(series, YAXIS.W.idx, visible);
         }
@@ -274,7 +266,7 @@
 
 
     /**
-     * Add Q-Series to plot.
+     * Add W/Q-Series to plot.
      * @param wqkms actual data
      * @param theme theme to use.
      */
@@ -284,7 +276,7 @@
         Document         theme,
         boolean          visible
     ) {
-        logger.debug("ComputedDischargeCurveGenerator: doQOut");
+        logger.debug("ComputedDischargeCurveGenerator: doQOut (add W/Q data).");
         XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
         StyledSeriesBuilder.addPointsQW(series, wqkms);
 
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java	Fri Jun 28 16:59:07 2013 +0200
@@ -14,12 +14,14 @@
 import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.jfree.Bounds;
 import org.dive4elements.river.jfree.RiverAnnotation;
+import org.dive4elements.river.jfree.StickyAxisAnnotation;
 import org.dive4elements.river.jfree.StyledXYSeries;
 import org.dive4elements.river.model.Gauge;
 import org.dive4elements.river.model.River;
 import org.dive4elements.river.utils.RiverUtils;
 
 import org.apache.log4j.Logger;
+import org.jfree.chart.annotations.XYTextAnnotation;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.Range;
@@ -37,8 +39,8 @@
 implements   FacetTypes {
 
     public static enum YAXIS {
-        W(0),
-        WCm(1);
+        WCm(0),
+        W(1);
         protected int idx;
         private YAXIS(int c) {
             idx = c;
@@ -66,6 +68,26 @@
     public static final String I18N_YAXIS_LABEL_DEFAULT  = "W [cm]";
 
 
+    /**
+     * Returns the PNP (Datum) of gauge, if at gauge, 0 otherwise.
+     */
+    public static double getCurrentGaugeDatum(double km, D4EArtifact artifact, double tolerance) {
+        // Code borrowed from FixATWriter.
+        Gauge gauge = RiverUtils.getGauge(artifact);
+        double subtractPNP = 0d;
+        if (Math.abs(km - gauge.getStation().doubleValue()) < tolerance) {
+            subtractPNP = gauge.getDatum().doubleValue();
+        }
+        return subtractPNP;
+    }
+
+
+    public double getCurrentGaugeDatum() {
+        return getCurrentGaugeDatum(getRange()[0],
+            (D4EArtifact) getMaster(), 1e-4);
+    }
+
+
     public DischargeCurveGenerator() {
         super();
     }
@@ -120,6 +142,23 @@
         return zoomin;
     }
 
+    public void translateRiverAnnotation(RiverAnnotation riverAnnotation) {
+        if (getCurrentGaugeDatum() == 0d) {
+            return;
+        }
+        logger.debug("Translate some river annotation.");
+        double translate = getCurrentGaugeDatum();
+        double factor    = 100d;
+        for (StickyAxisAnnotation annotation: riverAnnotation.getAxisTextAnnotations()){
+            if (!annotation.atX()) {
+                annotation.setPos((annotation.getPos() - translate)*factor);
+            }
+        }
+        for (XYTextAnnotation annotation: riverAnnotation.getTextAnnotations()) {
+            annotation.setY((annotation.getY() - translate)*factor);
+        }
+    }
+
 
     @Override
     public void doOut(
@@ -144,7 +183,10 @@
                 || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W)
                 || name.equals(MAINVALUES_W))
         {
-            doAnnotations((RiverAnnotation) artifactFacet.getData(context),
+            RiverAnnotation mainValues = (RiverAnnotation) artifactFacet.getData(context);
+            translateRiverAnnotation(mainValues);
+            doAnnotations(
+                mainValues,
                 artifactFacet, theme, visible);
         }
         else if (FacetTypes.IS.MANUALPOINTS(name)) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java	Fri Jun 28 16:59:07 2013 +0200
@@ -78,6 +78,37 @@
      * @param points Points to add to series, points[0] to 1st dim, points[1]
      *               to 2nd dim.
      * @param skipNANs if true, skip NAN values in points parameter.
+     * @param transY translate y-values by this value (before scale).
+     * @param factorY scale y-values by this value (after translation).
+     */
+    public static void addPoints(XYSeries series, double[][] points,
+        boolean skipNANs, double transY, double factorY) {
+        if (transY == 0d && factorY == 1d) {
+            addPoints(series, points, skipNANs);
+            return;
+        }
+        if (points == null || points.length <= 1) {
+            return;
+        }
+        double [] xPoints = points[0];
+        double [] yPoints = points[1];
+        for (int i = 0; i < xPoints.length; i++) {
+            if (skipNANs &&
+                (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) {
+                logger.warn ("Skipping NaN in StyledSeriesBuilder.");
+                continue;
+            }
+            series.add(xPoints[i], factorY * (transY+yPoints[i]), false);
+        }
+    }
+
+    /**
+     * Add points to series.
+     *
+     * @param series Series to add points to.
+     * @param points Points to add to series, points[0] to 1st dim, points[1]
+     *               to 2nd dim.
+     * @param skipNANs if true, skip NAN values in points parameter.
      */
     public static void addPoints(XYSeries series, double[][] points, boolean skipNANs) {
         if (points == null || points.length <= 1) {
@@ -254,6 +285,28 @@
         }
     }
 
+    /**
+     * Add points to series (q to 1st dim, w to 2nd dim), with
+     * scaling and translation.
+     *
+     * @param series Series to add points to.
+     * @param qs the Qs to add, assumed same length than ws.
+     * @param ws the Ws to add, assumed same length than qs.
+     */
+    public static void addPointsQW(XYSeries series, double[] qs, double ws[],
+        double wTrans, double wScale) {
+        if (ws == null || qs == null) {
+            return;
+        }
+
+        int size = qs.length;
+
+        for (int i = 0; i < size; i++) {
+            series.add(qs[i], wScale * (ws[i]+wTrans), false);
+        }
+    }
+
+
 
     /**
      * Add points to series (q to 1st dim, w to 2nd dim).
--- a/artifacts/src/main/java/org/dive4elements/river/exports/SyncNumberAxis.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/SyncNumberAxis.java	Fri Jun 28 16:59:07 2013 +0200
@@ -33,7 +33,7 @@
     protected double shift;
 
 
-    protected SyncNumberAxis(String key, String label, NumberAxis n) {
+    public SyncNumberAxis(String key, String label, NumberAxis n) {
         super(key, label);
         this.proxyAxis = n;
     }
@@ -48,7 +48,7 @@
     }
 
     /** Set value by which to translate the range. */
-    protected void setShift(double shift) {
+    public void setShift(double shift) {
         this.shift = shift;
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java	Fri Jun 28 16:59:07 2013 +0200
@@ -21,6 +21,7 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.river.artifacts.access.FixAnalysisAccess;
+import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.model.DateRange;
 import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.artifacts.model.extreme.Curve;
@@ -31,6 +32,7 @@
 import org.dive4elements.river.jfree.JFreeUtil;
 import org.dive4elements.river.jfree.StyledXYSeries;
 
+import org.dive4elements.river.utils.RiverUtils;
 import org.dive4elements.river.utils.ThemeUtil;
 
 
@@ -71,21 +73,23 @@
             "W [NN + m]";
 
 
+    /** First, ask parent to add data, then handle extreme_wq_curve(_base) data.*/
     @Override
     public boolean prepareChartData(ArtifactAndFacet aaf, Document theme, boolean visible) {
-        if (!super.prepareChartData(aaf, theme, visible)) {
-            String name = aaf.getFacetName();
-            if (name.equals(EXTREME_WQ_CURVE)) {
-                doExtremeCurveOut(aaf, theme, visible);
-                return true;
-            }
-            else if (name.equals(EXTREME_WQ_CURVE_BASE)) {
-                doExtremeCurveBaseOut(aaf, theme, visible);
-                return true;
-            }
-            return false;
+        if (super.prepareChartData(aaf, theme, visible)) {
+            return true;
         }
-        return true;
+
+        String name = aaf.getFacetName();
+        if (name.equals(EXTREME_WQ_CURVE)) {
+            doExtremeCurveOut(aaf, theme, visible);
+            return true;
+        }
+        else if (name.equals(EXTREME_WQ_CURVE_BASE)) {
+            doExtremeCurveBaseOut(aaf, theme, visible);
+            return true;
+        }
+        return false;
     }
 
     /** Do Extreme Curve nonextrapolated points out. */
@@ -99,9 +103,24 @@
         }
 
         XYSeries qwseries = new StyledXYSeries(aaf.getFacetDescription(), theme);
-        StyledSeriesBuilder.addPointsQW(qwseries, curve.getQs(), curve.getWs());
 
-        addAxisSeries(qwseries, YAXIS.W.idx, visible);
+        double gaugeDatum = getCurrentGaugeDatum();
+
+        if (gaugeDatum == 0d) {
+            StyledSeriesBuilder.addPointsQW(qwseries, curve.getQs(), curve.getWs());
+            addAxisSeries(qwseries, YAXIS.W.idx, visible);
+        }
+        else {
+            XYSeries series2 = new StyledXYSeries(aaf.getFacetDescription(), theme);
+            StyledSeriesBuilder.addPointsQW(series2, curve.getQs(), curve.getWs());
+            addAxisSeries(series2, YAXIS.W.idx, false);
+
+            StyledSeriesBuilder.addPointsQW(qwseries, curve.getQs(), curve.getWs(), -gaugeDatum, 100d);
+
+            addAxisSeries(qwseries, YAXIS.WCm.idx, visible);
+        }
+
+        //addAxisSeries(qwseries, YAXIS.W.idx, visible);
     }
 
 
@@ -138,7 +157,7 @@
             addDomainMarker(m);
         }
 
-        addAxisSeries(series, 0, visible);
+        addAxisSeries(series, YAXIS.W.idx, visible);
     }
 
 
@@ -196,7 +215,14 @@
 
     @Override
     protected String getDefaultYAxisLabel(int pos) {
-        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+        D4EArtifact flys = (D4EArtifact) master;
+
+        String unit = RiverUtils.getRiver(flys).getWstUnit().getName();
+        if (pos == 0) {
+            unit = "cm";
+        }
+
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT, new Object[] { unit });
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java	Fri Jun 28 16:59:07 2013 +0200
@@ -10,6 +10,7 @@
 
 import java.awt.BasicStroke;
 import java.awt.Color;
+import java.awt.Font;
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.List;
@@ -17,6 +18,7 @@
 import org.apache.log4j.Logger;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.plot.Marker;
 import org.jfree.chart.plot.ValueMarker;
 import org.jfree.chart.title.TextTitle;
@@ -44,6 +46,8 @@
 import org.dive4elements.river.artifacts.model.fixings.QWI;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.exports.ChartGenerator;
+import org.dive4elements.river.exports.DischargeCurveGenerator;
+import org.dive4elements.river.exports.SyncNumberAxis;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
 import org.dive4elements.river.jfree.RiverAnnotation;
@@ -94,7 +98,8 @@
     public static final double EPSILON = 0.001d;
 
     public static enum YAXIS {
-        W(0);
+        WCm(0),
+        W(1);
         public int idx;
         private YAXIS(int c) {
             idx = c;
@@ -105,6 +110,58 @@
     /** Needed to access data to create subtitle. */
     protected D4EArtifact artifact;
 
+    // TODO dupe of ComputedDischargeCurveGenerator
+    protected SyncNumberAxis secondYAxis;
+    // TODO dupe of ComputedDischargeCurveGenerator
+    protected NumberAxis firstYAxis;
+
+
+    /**
+     * Create Y (range) axis for given index, here with a special axis
+     * that depends on other axis (does translation and scaling for
+     * special case at gauge in cm).
+     */
+    // TODO dupe of ComputedDischargeCurveGenerator
+    @Override
+    protected NumberAxis createYAxis(int index) {
+        logger.debug("createYAxis: " + index);
+        if (index == 1) {
+            firstYAxis = super.createYAxis(1);
+            if (secondYAxis != null) {
+                secondYAxis.setProxyAxis(firstYAxis);
+            }
+            return firstYAxis;
+        }
+        YAxisWalker walker = getYAxisWalker();
+
+        Font labelFont = new Font(
+            DEFAULT_FONT_NAME,
+            Font.BOLD,
+            getYAxisFontSize(index));
+
+        SyncNumberAxis axis = new SyncNumberAxis(
+            walker.getId(index),
+            getYAxisLabel(index),
+            firstYAxis);
+
+        axis.setAutoRangeIncludesZero(false);
+        axis.setLabelFont(labelFont);
+        axis.setTickLabelFont(labelFont);
+        axis.setShift((double)-getCurrentGaugeDatum());
+
+        secondYAxis = axis;
+        return axis;
+    }
+
+    public double getCurrentGaugeDatum() {
+        if (context.getContextValue(CURRENT_KM) != null) {
+            return DischargeCurveGenerator.getCurrentGaugeDatum(
+                (Double) context.getContextValue(CURRENT_KM),
+                (D4EArtifact) getMaster(), 0.1d);
+        }
+        else return 0d;
+    }
+
 
     @Override
     public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
@@ -114,8 +171,10 @@
         }
     }
 
-
-    /** Return true if data could be handled. */
+    /**
+     * Return true if data could be handled,
+     * to be overridden to add more handled data.
+     */
     public boolean prepareChartData(ArtifactAndFacet aaf, Document doc, boolean visible) {
         String name = aaf.getFacetName();
 
@@ -153,10 +212,12 @@
                     visible);
         }
         else if (LONGITUDINAL_W.equals(name) || STATIC_WQ.equals(name)
-                        || STATIC_WKMS_INTERPOL.equals(name)) {
+                        || STATIC_WKMS_INTERPOL.equals(name)
+                        || FIX_WQ_LS.equals(name)) {
             doWQOut(aaf.getData(context), aaf, doc, visible);
         }
         else if (name.equals(DISCHARGE_CURVE)) {
+        logger.debug("diso " + name);
             doDischargeOut(
                     (WINFOArtifact) aaf.getArtifact(),
                     aaf.getData(context),
@@ -316,7 +377,20 @@
                     0.0 ,  // start
                     maxQ); // end
 
-            addAxisSeries(series, YAXIS.W.idx, visible);
+            double gaugeDatum = getCurrentGaugeDatum();
+
+            double factor = (gaugeDatum == 0d) ? 1d : 100d;
+
+            if (gaugeDatum == 0d) {
+                addAxisSeries(series, YAXIS.W.idx, visible);
+            }
+            else {
+                // Use second axis at cm if at gauge.
+                for (int i = 0; i < series.getItemCount(); i++) {
+                    series.updateByIndex(i, new Double(factor*(series.getY(i).doubleValue()-gaugeDatum)));
+                }
+                addAxisSeries(series, YAXIS.WCm.idx, visible);
+            }
         }
         else {
             logger.warn("doWQCurveOut: maxQ <= 0");
@@ -612,7 +686,14 @@
 
     @Override
     protected String getDefaultYAxisLabel(int pos) {
-        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+        D4EArtifact flys = (D4EArtifact) master;
+
+        String unit = RiverUtils.getRiver(flys).getWstUnit().getName();
+        if (pos == 0) {
+            unit = "cm";
+        }
+
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT, new Object[] { unit });
     }
 
     @Override
--- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSGenerator.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSGenerator.java	Fri Jun 28 16:59:07 2013 +0200
@@ -359,3 +359,4 @@
         }
     }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StickyAxisAnnotation.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StickyAxisAnnotation.java	Fri Jun 28 16:59:07 2013 +0200
@@ -95,14 +95,21 @@
     }
 
 
+    /** The position (relative to axis). */
     public float getPos() {
         return this.pos;
     }
 
+    /** The position (relative to axis). */
+    public void setPos(double pos) {
+        this.pos = (float) pos;
+    }
+
     public SimpleAxis getStickyAxis() {
         return this.stickyAxis;
     }
 
+    /** True if at x axis. */
     public boolean atX() {
         return this.getStickyAxis() == SimpleAxis.X_AXIS;
     }
--- a/artifacts/src/main/resources/messages.properties	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/resources/messages.properties	Fri Jun 28 16:59:07 2013 +0200
@@ -207,6 +207,9 @@
 chart.fixings.wq.subtitle=River: {0}; Range: {1,date,short} to {2,date,short}; Reference period: {3,date,short} to {4,date,short}
 chart.fixings.wq.subtitle1={0,date,short} to {1,date,short}
 chart.fixings.analysis.title = Longitudinal section at km {0}
+chart.fixings.wq.yaxis.label = W [{0}]
+
+chart.extreme.wq.yaxis.label = W [{0}]
 
 chart.bedquality.title=Bed Longitudinal Section
 chart.bedquality.xaxis.label={0}-km
@@ -433,6 +436,8 @@
 wsplgen.job.queued = WSPLGEN job in queue.
 wsplgen.job.error = An unexpected error while starting WSPLGEN occured.
 
+official.line.found = Found official line for {0}.
+
 wsp.selected.string = {0}
 
 Mosel = Mosel
--- a/artifacts/src/main/resources/messages_de.properties	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Fri Jun 28 16:59:07 2013 +0200
@@ -26,7 +26,7 @@
 state.winfo.reference.curve.input.end = Zielort(e)
 state.winfo.function_select = Funktion
 state.winfo.extreme.percent = Abstand zum letzten Extremwert in Prozent
-state.winfo.extreme.qinput = Eingabe f\u00e4r Q Daten
+state.winfo.extreme.qinput = Eingabe f\u00fcr Q Daten
 state.fix.river = Gew\u00e4sser
 state.fix.calculation.mode = Berechnungsart
 state.fix.location = Strecke
@@ -195,7 +195,9 @@
 chart.fixings.deltawt.title = Abweichungen von der Ausgleichskurve an Kilometer {0}
 chart.fixings.analysis.title = L\u00e4ngsschnitt an Kilometer {0}
 chart.fixings.wq.title = Fixierungsanalyse an Kilometer {0}
+chart.fixings.wq.yaxis.label = W [{0}]
 
+chart.extreme.wq.yaxis.label = W [{0}]
 
 chart.reference.curve.x.axis.in.cm = Bezugspegel [cm]
 chart.reference.curve.x.axis.in.m = Bezugsort [NN + m]
@@ -434,6 +436,8 @@
 wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange.
 wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten.
 
+official.line.found = Es existiert eine amtliche Festlegung f\u00fcr {0}.
+
 wsp.selected.string = {0}
 
 Mosel = Mosel
--- a/artifacts/src/main/resources/messages_de_DE.properties	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/resources/messages_de_DE.properties	Fri Jun 28 16:59:07 2013 +0200
@@ -26,7 +26,7 @@
 state.winfo.reference.curve.input.end = Zielort(e)
 state.winfo.function_select = Funktion
 state.winfo.extreme.percent = Abstand zum letzten Extremwert in Prozent
-state.winfo.extreme.qinput = Eingabe f\u00e4r Q Daten
+state.winfo.extreme.qinput = Eingabe f\u00fcr Q Daten
 state.fix.river = Gew\u00e4sser
 state.fix.calculation.mode = Berechnungsart
 state.fix.location = Strecke
@@ -198,6 +198,9 @@
 chart.fixings.derivedcurve.title = Ableitungskurve an Kilometer {0}
 chart.fixings.analysis.title = L\u00e4ngsschnitt an Kilometer {0}
 chart.fixings.wq.title = Fixierungsanalyse an Kilometer {0}
+chart.fixings.wq.yaxis.label = W [{0}]
+
+chart.extreme.wq.yaxis.label = W [{0}]
 
 chart.normalized.reference.curve.title = Reduzierte Bezugslinie
 
@@ -430,6 +433,8 @@
 wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange.
 wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten.
 
+official.line.found = Es existiert eine amtliche Festlegung f\u00fcr {0}.
+
 wsp.selected.string = {0}
 
 Mosel = Mosel
--- a/artifacts/src/main/resources/messages_en.properties	Fri Jun 28 16:58:46 2013 +0200
+++ b/artifacts/src/main/resources/messages_en.properties	Fri Jun 28 16:59:07 2013 +0200
@@ -197,6 +197,9 @@
 chart.fixings.derivedcurve.title = Derived curve at km {0}
 chart.fixings.deltawt.title = Differences from fitted curve at km {0}
 chart.fixings.wq.title = Fixings Analysis at km {0}
+chart.fixings.wq.yaxis.label = W [{0}]
+
+chart.extreme.wq.yaxis.label = W [{0}]
 
 chart.reference.curve.x.axis.in.cm = Reference Gauge(s) [cm]
 chart.reference.curve.x.axis.in.m = Reference Station [NN + m]
@@ -435,6 +438,8 @@
 wsplgen.job.queued = WSPLGEN job in queue.
 wsplgen.job.error = An unexpected error while starting WSPLGEN occured.
 
+official.line.found = Found official line for {0}.
+
 wsp.selected.string = {0}
 
 Mosel = Mosel
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/Config.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/Config.java	Fri Jun 28 16:59:07 2013 +0200
@@ -29,6 +29,7 @@
     /** The xml document that contains the configuration options. */
     protected Document config;
 
+    protected String helpUrl;
 
     /**
      * Get an instance by using {@link getInstance(Document)} or {@link
@@ -85,8 +86,11 @@
      * @return wiki base URL
      */
     public String getWikiUrl() {
-        Node server = config.getElementsByTagName("wiki").item(0);
-        return server.getFirstChild().getNodeValue();
+        return this.helpUrl;
+    }
+
+    public void setWikiUrl(String url) {
+        this.helpUrl = url;
     }
 
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYS.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYS.java	Fri Jun 28 16:59:07 2013 +0200
@@ -13,7 +13,6 @@
 import com.google.gwt.event.shared.UmbrellaException;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.xml.client.XMLParser;
-
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.HTMLPane;
 import com.smartgwt.client.widgets.Window;
@@ -21,6 +20,12 @@
 import com.smartgwt.client.widgets.events.CloseClickHandler;
 import com.smartgwt.client.widgets.layout.VLayout;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Set;
+
 import org.dive4elements.river.client.client.event.CollectionChangeEvent;
 import org.dive4elements.river.client.client.event.CollectionChangeHandler;
 import org.dive4elements.river.client.client.services.ArtifactService;
@@ -33,6 +38,8 @@
 import org.dive4elements.river.client.client.services.GetArtifactServiceAsync;
 import org.dive4elements.river.client.client.services.RiverService;
 import org.dive4elements.river.client.client.services.RiverServiceAsync;
+import org.dive4elements.river.client.client.services.ServerInfoService;
+import org.dive4elements.river.client.client.services.ServerInfoServiceAsync;
 import org.dive4elements.river.client.client.services.UserService;
 import org.dive4elements.river.client.client.services.UserServiceAsync;
 import org.dive4elements.river.client.client.ui.CollectionView;
@@ -40,6 +47,7 @@
 import org.dive4elements.river.client.client.ui.FLYSView;
 import org.dive4elements.river.client.client.ui.FLYSWorkspace;
 import org.dive4elements.river.client.client.ui.ProjectList;
+import org.dive4elements.river.client.client.ui.wq.WQAutoTabSet;
 import org.dive4elements.river.client.shared.model.Artifact;
 import org.dive4elements.river.client.shared.model.Collection;
 import org.dive4elements.river.client.shared.model.CollectionItem;
@@ -47,13 +55,6 @@
 import org.dive4elements.river.client.shared.model.River;
 import org.dive4elements.river.client.shared.model.User;
 
-import org.dive4elements.river.client.client.ui.wq.WQAutoTabSet;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.MissingResourceException;
-import java.util.Set;
-
 
 /**
  * Entry point classes define <code>onModuleLoad()</code>.
@@ -68,6 +69,8 @@
     /** The UserService used to retrieve information about the current user. */
     protected UserServiceAsync userService = GWT.create(UserService.class);
 
+    protected ServerInfoServiceAsync serverInfoService = GWT.create(ServerInfoService.class);
+
     /** The RiverService used to retrieve the supported rivers of the server.*/
     protected RiverServiceAsync riverService = GWT.create(RiverService.class);
 
@@ -135,6 +138,8 @@
         //    }
         //});
 
+        initConfiguration();
+
         VLayout vertical = new VLayout();
         vertical.setLayoutMargin(1);
         vertical.setWidth100();
@@ -148,11 +153,32 @@
 
         vertical.draw();
 
-        initConfiguration();
+        Config config = Config.getInstance();
+        final String locale = config.getLocale();
 
-        Config config = Config.getInstance();
-        String locale = config.getLocale();
+        serverInfoService.getConfig(locale, new AsyncCallback<Map<String,String>>() {
 
+            @Override
+            public void onSuccess(Map<String, String> result) {
+                GWT.log("serverInfoService.callBack.onSuccess");
+                GWT.log("help-url=" + result.get("help-url"));
+                Config.getInstance().setWikiUrl(result.get("help-url"));
+
+                // Start user service; somewhat nested here...
+                startUserService(locale);
+            }
+
+            @Override
+            public void onFailure(Throwable caught) {
+               GWT.log("Could not read server information.");
+               String msg = getExceptionString(MSG, caught);
+               SC.warn(msg);
+               startUserService(locale);
+            }
+        });
+    }
+
+    protected void startUserService(String locale) {
         userService.getCurrentUser(locale, new AsyncCallback<User>() {
             @Override
             public void onFailure(Throwable caught) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/ServerInfoService.java	Fri Jun 28 16:59:07 2013 +0200
@@ -0,0 +1,18 @@
+package org.dive4elements.river.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import java.util.Map;
+
+/**
+ * Service that provides server configuration values relevant to the client.
+ *
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ *
+ */
+@RemoteServiceRelativePath("server-info")
+public interface ServerInfoService extends RemoteService {
+
+    Map<String, String> getConfig(String locale);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/ServerInfoServiceAsync.java	Fri Jun 28 16:59:07 2013 +0200
@@ -0,0 +1,12 @@
+package org.dive4elements.river.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import java.util.Map;
+
+public interface ServerInfoServiceAsync {
+
+    public void getConfig(
+            String locale,
+            AsyncCallback<Map<String, String>> cfg);
+}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/ArtifactHelper.java	Fri Jun 28 16:58:46 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/ArtifactHelper.java	Fri Jun 28 16:59:07 2013 +0200
@@ -16,6 +16,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Semaphore;
 
 import org.dive4elements.artifacts.common.utils.ClientProtocolUtils;
 import org.dive4elements.artifacts.common.utils.CreationFilter;
@@ -52,6 +53,12 @@
 
     private static final String SQ_RELATION_ARTIFACT = "staticsqrelation";
 
+    // To prevent pile up of create artifact calls only permit a limited
+    // number of parallel creates.
+    public static final int MAX_CREATE = 5;
+
+    private static final Semaphore CREATE_SEMAPHORE = new Semaphore(MAX_CREATE);
+
     private ArtifactHelper() {
     }
 
@@ -90,7 +97,6 @@
             factory, uuid, ids, filter, targetOut);
 
         return sendCreate(serverUrl, locale, create);
-
     }
 
     /**
@@ -170,16 +176,27 @@
             Document doc)
     throws ServerException
     {
-        HttpClient client = new HttpClientImpl(serverUrl, locale);
-
         try {
-            return (Artifact) client.create(doc, new FLYSArtifactCreator());
+            CREATE_SEMAPHORE.acquire();
         }
-        catch (ConnectionException ce) {
-            logger.error(ce, ce);
+        catch (InterruptedException ie) {
+            throw new ServerException(ERROR_CREATE_ARTIFACT);
         }
+        try {
+            HttpClient client = new HttpClientImpl(serverUrl, locale);
 
-        throw new ServerException(ERROR_CREATE_ARTIFACT);
+            try {
+                return (Artifact) client.create(doc, new FLYSArtifactCreator());
+            }
+            catch (ConnectionException ce) {
+                logger.error(ce, ce);
+            }
+
+            throw new ServerException(ERROR_CREATE_ARTIFACT);
+        }
+        finally {
+            CREATE_SEMAPHORE.release();
+        }
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/ServerInfoServiceImpl.java	Fri Jun 28 16:59:07 2013 +0200
@@ -0,0 +1,69 @@
+package org.dive4elements.river.client.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+import org.dive4elements.artifacts.httpclient.http.HttpClient;
+import org.dive4elements.artifacts.httpclient.http.HttpClientImpl;
+import org.dive4elements.river.client.client.services.ServerInfoService;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class ServerInfoServiceImpl extends RemoteServiceServlet implements
+        ServerInfoService {
+
+    // This works only because currently there is only one info transmitted
+    private static final String XPATH_INFO = "/art:server/art:info";
+
+    private final Logger logger = Logger.getLogger(ServerInfoServiceImpl.class);
+
+    @Override
+    public Map<String, String> getConfig(String locale) {
+        Map<String, String> infoMap = new HashMap<String, String>();
+        String url = getServletContext().getInitParameter("server-url");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        doc.appendChild(ec.create("action"));
+
+        HttpClient client = new HttpClientImpl(url, locale);
+
+        try {
+            Document res = client.callService(url, "server-info", doc);
+
+            NodeList info = (NodeList) XMLUtils.xpath(res,
+                    XPATH_INFO,
+                    XPathConstants.NODESET,
+                    ArtifactNamespaceContext.INSTANCE);
+
+            for (int n = 0; n < info.getLength(); n++) {
+                Element el = (Element)info.item(n);
+                String key = el.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "key");
+                String val = el.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "value");
+                infoMap.put(key, val);
+
+                logger.debug("ServerInfoServiceImpl: " + key + "=" + val);
+            }
+        }
+        catch (Exception ex) {
+            logger.error(ex, ex);
+        }
+
+        return infoMap;
+    }
+
+
+}
--- a/gwt-client/src/main/webapp/WEB-INF/web.xml	Fri Jun 28 16:58:46 2013 +0200
+++ b/gwt-client/src/main/webapp/WEB-INF/web.xml	Fri Jun 28 16:59:07 2013 +0200
@@ -53,6 +53,16 @@
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>server-info</servlet-name>
+    <servlet-class>org.dive4elements.river.client.server.ServerInfoServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>server-info</servlet-name>
+    <url-pattern>/flys/server-info</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>artifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ArtifactServiceImpl</servlet-class>
   </servlet>
Binary file gwt-client/src/main/webapp/images/FLYS_Saale_1_inactive.png has changed

http://dive4elements.wald.intevation.org