changeset 3614:68beaa827751

MINFO: Implemented UI and facet/artifact stack for bed height differences. flys-artifacts/trunk@5276 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Tue, 28 Aug 2012 11:45:23 +0000
parents dd6e25980c91
children f84854eba0b3
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/artifacts/minfo.xml flys-artifacts/doc/conf/conf.xml flys-artifacts/doc/conf/meta-data.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticBedHeightCacheKey.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java flys-artifacts/src/main/resources/messages.properties flys-artifacts/src/main/resources/messages_de.properties flys-artifacts/src/main/resources/messages_de_DE.properties flys-artifacts/src/main/resources/messages_en.properties
diffstat 18 files changed, 885 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/ChangeLog	Tue Aug 28 11:45:23 2012 +0000
@@ -1,3 +1,43 @@
+2012-08-28  Raimund Renkert <raimund.renkert@intevation.de>
+
+	MINFO: Implemented UI and facet/artifact stack for bed height differences.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/StaticBedHeightCacheKey.java:
+	  New. Facet and data object incl. factory for bed heights.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java,
+	  src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java:
+	  New. States for difference calculation mode and new artifact for difference
+	  selection.
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java:
+	  Added getter for time (year or epoch).
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new facet type.
+
+	* doc/conf/meta-data.xml:
+	  Datacage config for minfo bed heights.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added transitions and states for minfo difference calculation.
+
+	* doc/conf/conf.xml:
+	  Added artifact factory.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Added i18n strings.
+
 2012-08-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
 
 	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
--- a/flys-artifacts/doc/conf/artifacts/minfo.xml	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/doc/conf/artifacts/minfo.xml	Tue Aug 28 11:45:23 2012 +0000
@@ -33,11 +33,21 @@
             <condition data="calculation_mode" value="calc.sq.relation" operator="equal"/>
         </transition>
 
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.calculation_mode"/>
+            <to state="state.minfo.bed.year_epoch"/>
+            <condition data="calculation_mode" value="calc.bed.diff" operator="equal"/>
+        </transition>
+
         <state id="state.minfo.distance_only" description="state.minfo.distance_only" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.minfo.distance">
             <data name="ld_from" type="Double" />
             <data name="ld_to"   type="Double" />
         </state>
 
+        <state id="state.minfo.bed.year_epoch" description="state.minfo.bed.year_epoch" state="de.intevation.flys.artifacts.states.minfo.YearEpochSelect" helpText="help.minfo.year_epoch">
+            <data name="ye_select" type="String" />
+        </state>
+
         <state id="state.minfo.sq.location" description="state.minfo.sq.location" state="de.intevation.flys.artifacts.states.LocationSelect" helpText="help.minfo.sq.loaction">
             <data name="ld_locations" type="double"/>
         </state>
@@ -59,6 +69,11 @@
             <to state="state.minfo.sq.period"/>
         </transition>
 
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.bed.year_epoch"/>
+            <to state="state.minfo.bed.difference_select"/>
+        </transition>
+
         <state id="state.minfo.dischargestate" description="state.minfo.dischargestate" state="de.intevation.flys.artifacts.states.DischargeState" helpText="help.minfo.dischargestate">
             <data name="total.channel" type="intoptions"/>
             <data name="main.channel"  type="intoptions"/>
@@ -73,6 +88,10 @@
             <data name="end"   type="Long"/>
         </state>
 
+        <state id="state.minfo.bed.difference_select" description="state.minfo.bed.difference_select" state="de.intevation.flys.artifacts.states.minfo.DifferenceSelect" helpText="help.minfo.diff_select">
+            <data name="diffids" type="String" />
+        </state>
+
         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.minfo.dischargestate"/>
             <to state="state.minfo.flow_velocity"/>
@@ -88,6 +107,11 @@
             <to state="state.minfo.sq.outliers"/>
         </transition>
 
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.bed.difference_select"/>
+            <to state="state.minfo.bed.differences"/>
+        </transition>
+
         <state id="state.minfo.flow_velocity" description="state.minfo.flow_velocity" state="de.intevation.flys.artifacts.states.FlowVelocityState" helpText="help.minfo.flowvelocity">
             <outputmodes>
                 <outputmode name="flow_velocity" description="output.flow_velocity" mime-type="image/png" type="chart">
@@ -131,6 +155,19 @@
             <data name="outliers" type="Double"/>
         </state>
 
+        <state id="state.minfo.bed.differences" description="state.minfo.bed.differences" state="de.intevation.flys.artifacts.states.minfo.DifferencesState" helpText="help.minfo.bed.differences">
+            <outputmodes>
+                <outputmode name="absolute_height" description="output.absolute_height" mime-type="image/png" type="chart">
+                    <facets>
+                    </facets>
+                </outputmode>
+                <outputmode name="difference_year" description="output.difference_year" mime-type="img/png" type="chart">
+                    <facets>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.minfo.sq.outliers"/>
             <to state="state.minfo.sq.relation"/>
--- a/flys-artifacts/doc/conf/conf.xml	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/doc/conf/conf.xml	Tue Aug 28 11:45:23 2012 +0000
@@ -118,6 +118,9 @@
             <artifact-factory name="minfo" description="Factory to create an artifact to be used in module minfo."
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.MINFOArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="bedheight" description="Factory to create an artifact used in minfo datacage."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.BedHeightsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
         </artifact-factories>
 
         <user-factory name="default" description="Factory to create new users">de.intevation.artifactdatabase.DefaultUserFactory</user-factory>
--- a/flys-artifacts/doc/conf/meta-data.xml	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/doc/conf/meta-data.xml	Tue Aug 28 11:45:23 2012 +0000
@@ -1224,6 +1224,58 @@
                   </rastermap>
               </dc:macro>
           </dc:if>
+          <dc:if test="dc:contains($artifact-outs, 'minfo-heights')">
+            <dc:call-macro name="minfo-heights"/>
+            <dc:macro name="minfo-heights">
+              <bedheights>
+                <dc:call-macro name="bed-heights-single"/>
+                <dc:call-macro name="bed-heights-epoch"/>
+              </bedheights>
+            </dc:macro>
+          </dc:if>
+          <dc:if test="dc:contains($artifact-outs, 'minfo-heights-epoch')">
+            <bedheights>
+              <dc:call-macro name="bed-heights-epoch"/>
+            </bedheights>
+          </dc:if>
+          <dc:macro name="bed-heights-single">
+            <single>
+              <dc:context>
+                <dc:statement>
+                    SELECT id          AS bedh_id,
+                           year        AS bedh_year,
+                           description AS bedh_descr
+                    FROM bed_height_single WHERE river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <height>
+                    <dc:attribute name="factory" value="bedheight"/>
+                    <dc:attribute name="ids" value="bedheight-single-${bedh_id}-${bedh_year}"/>
+                    <dc:attribute name="description" value="${bedh_descr}"/>
+                  </height>
+                </dc:elements>
+              </dc:context>
+            </single>
+          </dc:macro>
+          <dc:macro name="bed-heights-epoch">
+            <epoch>
+              <dc:context>
+                <dc:statement>
+                  SELECT id               AS bedh_id,
+                         time_interval_id AS bedh_interval_id,
+                         description      AS bedh_descr
+                  FROM bed_height_epoch WHERE river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <height>
+                    <dc:attribute name="factory" value="bedheight"/>
+                    <dc:attribute name="ids" value="bedheight-epoch-${bedh_id}-${bedh_interval_id}"/>
+                    <dc:attribute name="description" value="${bedh_descr}"/>
+                  </height>
+                </dc:elements>
+              </dc:context>
+            </epoch>
+          </dc:macro>
         </river>
       </dc:elements>
     </dc:context>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,165 @@
+package de.intevation.flys.artifacts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedHeight;
+import de.intevation.flys.artifacts.model.minfo.BedHeightFacet;
+import de.intevation.flys.artifacts.model.minfo.BedHeightFactory;
+import de.intevation.flys.artifacts.states.StaticState;
+
+public class BedHeightsArtifact
+extends      StaticFLYSArtifact
+implements   FacetTypes
+{
+    /** The logger for this class. */
+    private static Logger logger =
+        Logger.getLogger(BedHeightsArtifact.class);
+
+    private static final String NAME = "bedheights";
+
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(NAME, FacetActivity.INACTIVE);
+    }
+
+    public static final String STATIC_STATE_NAME =
+        "state.additional_bedheights.static";
+
+    /** Data Item name to know whether we are Heighmarks and reveive
+     * some data slightly different. */
+    public static final String DATA_HEIGHT_TYPE =
+        "height_marks";
+
+    /** One and only state to be in. */
+    protected transient State state = null;
+
+
+    /**
+     * Trivial Constructor.
+     */
+    public BedHeightsArtifact() {
+        logger.debug("BedHeightsArtifact.BedHeightsArtifact");
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    /**
+     * Gets called from factory, to set things up.
+     */
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("BedHeightsArtifact.setup");
+
+        state = new StaticState(STATIC_STATE_NAME);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(XMLUtils.toString(data));
+        }
+
+        List<Facet> fs = new ArrayList<Facet>();
+        String code = getDatacageIDValue(data);
+
+        if (code != null) {
+            String [] parts = code.split("-");
+
+            if (parts.length >= 4) {
+                if (parts[0].equals("bedheight")) {
+                    addStringData("type", parts[1]);
+                    addStringData("height_id", parts[2]);
+                    addStringData("time", parts[3]);
+                }
+                int hId = Integer.parseInt(parts[2]);
+                String bedHName = BedHeightFactory.getHeightName(parts[1], hId);
+
+                Facet bedHFacet = new BedHeightFacet(
+                    "bedheight",
+                    bedHName);
+
+                fs.add(bedHFacet);
+                facets.put(state.getID(), fs);
+            }
+        }
+
+        //spawnState();
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+    /**
+     * Get a list containing the one and only State.
+     * @param  context ignored.
+     * @return list with one and only state.
+     */
+    @Override
+    protected List<State> getStates(Object context) {
+        ArrayList<State> states = new ArrayList<State>();
+        states.add(getState());
+        return states;
+    }
+
+    /**
+     * Get the "current" state (there is but one).
+     * @param cc ignored.
+     * @return the "current" (only possible) state.
+     */
+    @Override
+    public State getCurrentState(Object cc) {
+        return getState();
+    }
+
+
+    /**
+     * Get the only possible state.
+     * @return the state.
+     */
+    protected State getState() {
+        return getState(null, null);
+    }
+
+
+    /**
+     * Get the state.
+     * @param context ignored.
+     * @param stateID ignored.
+     * @return the state.
+     */
+    @Override
+    protected State getState(Object context, String stateID) {
+        return (state != null)
+            ? state
+            : new StaticState(STATIC_STATE_NAME);
+    }
+
+    /**
+     * Get WKms from factory.
+     * @param idx param is not needed (TODO?)
+     * @return WKms according to parameterization (can be null);
+     */
+    public BedHeight getHeight() {
+        return BedHeightFactory.getHeight(
+            getDataAsString("type"),
+            Integer.parseInt(getDataAsString("height_id")),
+            Integer.parseInt(getDataAsString("time")));
+    }
+
+}
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java	Tue Aug 28 11:45:23 2012 +0000
@@ -18,6 +18,7 @@
     private Double lowerKM;
     private Double upperKM;
 
+    private String time;
 
     public BedHeightAccess(FLYSArtifact artifact) {
         super(artifact);
@@ -75,6 +76,14 @@
     }
 
 
+    public String getYearEpoch() {
+        if (time == null) {
+            time =  getString("ye_select");
+        }
+        return time;
+    }
+
+
     public int[] getBedHeightEpochIDs() {
         if (epochIDs == null) {
             String data = getString("soundings");
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Tue Aug 28 11:45:23 2012 +0000
@@ -281,5 +281,7 @@
     String FIX_DEVIATION_LS = "fix_deviation_ls";
 
     String FIX_PARAMETERS = "fix_parameters";
+    
+    String STATIC_BEDHEIGHT = "static_bedheight";
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticBedHeightCacheKey.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,28 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+public class StaticBedHeightCacheKey implements Serializable {
+    public static final String CACHE_NAME = "bedheight-value-table-static";
+
+    private int time;
+    private int height_id;
+
+    public StaticBedHeightCacheKey(int column, int wst_id) {
+        this.height_id  = wst_id;
+        this.time  = column;
+    }
+
+    public int hashCode() {
+        return (height_id << 8) | time;
+    }
+
+    public boolean equals(Object other) {
+        if (!(other instanceof StaticBedHeightCacheKey)) {
+            return false;
+        }
+        StaticBedHeightCacheKey o = (StaticBedHeightCacheKey) other;
+        return this.height_id == o.height_id && this.time == o.time;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,103 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import gnu.trove.TDoubleArrayList;
+import de.intevation.flys.artifacts.model.NamedObjectImpl;
+
+public class BedHeight
+extends NamedObjectImpl 
+{
+    private static Logger log = Logger.getLogger(BedHeight.class);
+
+    protected TDoubleArrayList heights;
+    protected TDoubleArrayList station;
+    protected TDoubleArrayList data_gap;
+
+    public BedHeight() {
+        heights = new TDoubleArrayList();
+        station = new TDoubleArrayList();
+        data_gap = new TDoubleArrayList();
+    }
+
+    public BedHeight(String name) {
+        super(name);
+        heights = new TDoubleArrayList();
+        station = new TDoubleArrayList();
+        data_gap = new TDoubleArrayList();
+    }
+
+    public BedHeight(int capacity) {
+        this(capacity, "");
+    }
+
+    public BedHeight(int capacity, String name) {
+        super(name);
+        heights = new TDoubleArrayList(capacity);
+        station = new TDoubleArrayList(capacity);
+        data_gap = new TDoubleArrayList(capacity);
+    }
+
+    public void add(double value, double station, double gap) {
+        this.heights.add(value);
+        this.station.add(station);
+        this.data_gap.add(gap);
+    }
+
+    public int size() {
+        return heights.size();
+    }
+
+    public double getHeight(int idx) {
+        return heights.getQuick(idx);
+    }
+
+    public double [] getHeights() {
+        return heights.toNativeArray();
+    }
+
+    public double [] get(int idx) {
+        return get(idx, new double [3]);
+    }
+
+    public double [] get(int idx, double [] dst) {
+        dst[0] = heights.getQuick(idx);
+        dst[1] = station.getQuick(idx);
+        dst[2] = data_gap.getQuick(idx);
+        return dst;
+    }
+
+    public double minHeights() {
+        return heights.min();
+    }
+
+    public static void removeNaNs(TDoubleArrayList [] arrays) {
+
+        int dest = 0;
+
+        int A = arrays.length;
+        int N = arrays[0].size();
+
+        OUTER: for (int i = 0; i < N; ++i) {
+            for (int j = 0; j < A; ++j) {
+                TDoubleArrayList a = arrays[j];
+                double v = a.getQuick(i);
+                if (Double.isNaN(v)) {
+                    continue OUTER;
+                }
+                a.setQuick(dest, v);
+            }
+            ++dest;
+        }
+
+        if (dest < N) {
+            for (int i = 0; i < A; ++i) {
+                arrays[i].remove(dest, N-dest);
+            }
+        }
+    }
+
+    public void removeNaNs() {
+        removeNaNs(new TDoubleArrayList [] { heights });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,48 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.BedHeightsArtifact;
+import de.intevation.flys.artifacts.model.BlackboardDataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+public class BedHeightFacet
+extends      BlackboardDataFacet
+implements   FacetTypes {
+
+    public BedHeightFacet(String description) {
+        this(STATIC_BEDHEIGHT, description);
+    }
+ 
+    public BedHeightFacet(String name, String description) {
+        this.name = name;
+        this.description = description;
+        this.index = 0;
+    }
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext (ignored).
+     *
+     * @return the data.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        BedHeightsArtifact staticData =
+            (BedHeightsArtifact) artifact;
+        return staticData.getHeight();
+    }
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public BedHeightFacet deepCopy() {
+        BedHeightFacet copy = new BedHeightFacet(description);
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,156 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+
+import java.util.List;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+import de.intevation.flys.artifacts.model.StaticBedHeightCacheKey;
+import de.intevation.flys.backend.SessionHolder;
+
+public class BedHeightFactory {
+    /** Private logger to use here. */
+    private static Logger log = Logger.getLogger(BedHeightFactory.class);
+
+    /** Query to get km and ws for wst_id and column_pos. */
+    public static final String SQL_SELECT_SINGLE =
+        "SELECT height, station, data_gap FROM bed_height_single_values " +
+        "WHERE id = :height_id";
+
+    /** Query to get name for wst_id and column_pos. */
+    public static final String SQL_SELECT_EPOCH =
+        "SELECT height, station FROM bed_height_epoch_values "+
+        "WHERE id = :height_id";
+
+    /** Query to get name (description) for wst_id. */
+    public static final String SQL_SELECT_DESCR_SINGLE =
+        "SELECT description FROM bed_height_single "+
+        "WHERE id = :height_id";
+
+    /** Query to get name (description) for wst_id. */
+    public static final String SQL_SELECT_DESCR_EPOCH =
+        "SELECT description from bed_height_epoch "+
+        "WHERE id = :height_id";
+
+
+    private BedHeightFactory() {
+    }
+
+
+    /**
+     * Get WKms for given column and wst_id, caring about the cache.
+     */
+    public static BedHeight getHeight(String type, int height_id, int time) {
+        log.debug("BedHeightFactory.getHeight");
+        Cache cache = CacheFactory.getCache(StaticBedHeightCacheKey.CACHE_NAME);
+
+        StaticBedHeightCacheKey cacheKey;
+
+        if (cache != null) {
+            cacheKey = new StaticBedHeightCacheKey(height_id, time);
+            Element element = cache.get(cacheKey);
+            if (element != null) {
+                log.debug("Got static bedheight values from cache");
+                return (BedHeight)element.getValue();
+            }
+        }
+        else {
+            cacheKey = null;
+        }
+
+        BedHeight values = getBedHeightUncached(type, height_id, time);
+
+        if (values != null && cacheKey != null) {
+            log.debug("Store static bed height values in cache.");
+            Element element = new Element(cacheKey, values);
+            cache.put(element);
+        }
+        return values;
+    }
+
+    /** Get name for a WKms. */
+    public static String getHeightName(String type, int height_id) {
+        log.debug("BedHeightFactory.getHeightName height_id/" + height_id);
+
+        String name = null;
+        Session session = SessionHolder.HOLDER.get();
+
+        SQLQuery nameQuery = null;
+        if (type.equals("single")) {
+            nameQuery = session.createSQLQuery(SQL_SELECT_DESCR_SINGLE)
+                .addScalar("description", StandardBasicTypes.STRING);
+            nameQuery.setInteger("height_id", height_id);
+        }
+        else if (type.equals("epoch")) {
+            nameQuery = session.createSQLQuery(SQL_SELECT_DESCR_EPOCH)
+                .addScalar("description", StandardBasicTypes.STRING);
+            nameQuery.setInteger("height_id", height_id);
+        }
+        else {
+            return "none";
+        }
+        List<String> names = nameQuery.list();
+        if (names.size() >= 1) {
+            name = names.get(0);
+        }
+
+        return name;
+    }
+
+
+    /**
+     * Get WKms from db.
+     * @param column the position columns value
+     * @param wst_id database id of the wst
+     * @return according WKms.
+     */
+    public static BedHeight getBedHeightUncached(
+        String type,
+        int height_id,
+        int time)
+    {
+        if (log.isDebugEnabled()) {
+            log.debug("BedHeightFactory.getBedHeightUncached");
+        }
+
+        BedHeight height = new BedHeight(getHeightName(type, height_id));
+
+        Session session = SessionHolder.HOLDER.get();
+        SQLQuery sqlQuery = null;
+        if (type.equals("single")) {
+            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLE)
+                .addScalar("height", StandardBasicTypes.DOUBLE)
+                .addScalar("station", StandardBasicTypes.DOUBLE)
+                .addScalar("data_gap", StandardBasicTypes.DOUBLE);
+            sqlQuery.setInteger("height_id", height_id);
+            List<Object []> results = sqlQuery.list();
+
+            for (int i = 0; i <= results.size(); i++) {
+                Object[] row = results.get(i);
+                height.add((Double) row[0], (Double) row[1], (Double) row[2]);
+            }
+        }
+        else if (type.equals("epoch")) {
+            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCH)
+                .addScalar("height", StandardBasicTypes.DOUBLE)
+                .addScalar("station", StandardBasicTypes.DOUBLE);
+            sqlQuery.setInteger("height_id", height_id);
+            List<Object []> results = sqlQuery.list();
+
+            for (int i = 0; i <= results.size(); i++) {
+                Object[] row = results.get(i);
+                height.add((Double) row[0], (Double) row[1], 0);
+            }
+        }
+
+        return height;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,139 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.BedHeightAccess;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.utils.StringUtil;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DifferenceSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(DifferenceSelect.class);
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public DifferenceSelect() {
+    }
+    /**
+     *  Specify to display nothing (this is kind of a "final" state).
+     */
+    @Override
+    protected String getUIProvider() {
+        return "bedheights_twin_panel";
+    }
+
+    /**
+     * Overridden to do nothing.
+     */
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        //Get data and do stuff, do not calculate
+        return "";
+    }
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator ec,
+        Artifact                artifact,
+        String                  name,
+        CallContext             context)
+    {
+        Element[] elements = new Element[1];
+        BedHeightAccess bha = new BedHeightAccess((FLYSArtifact)artifact);
+        String time = bha.getYearEpoch();
+        elements[0] = createItem(
+            ec,
+            new String[] {"year-epoch", time});
+
+        return elements;
+    }
+
+    /**
+     * Creates the data element used for the static part of DESCRIBE document.
+     */
+    @Override
+    protected Element createStaticData(
+        FLYSArtifact   flys,
+        ElementCreator creator,
+        CallContext    cc,
+        String         name,
+        String         value,
+        String         type
+    ) {
+        Element dataElement = creator.create("data");
+        creator.addAttr(dataElement, "name", name, true);
+        creator.addAttr(dataElement, "type", type, true);
+
+        Element itemElement = creator.create("item");
+        creator.addAttr(itemElement, "value", value, true);
+
+        String[] labels = getLabels(cc, value);
+
+        creator.addAttr(
+            itemElement,
+            "label",
+            labels[0],
+            true);
+        dataElement.appendChild(itemElement);
+
+        return dataElement;
+    }
+
+
+    /**
+     * Get name to display for selected watelerlevels (for example "Q=123")
+     * from the CalculationResult.
+     */
+    public static String[] getLabels(CallContext cc, String value) {
+        String[] recommendations = value.split("#");
+        String displayString = "";
+
+        // Walk over all selected recommendations and create label
+        for (int i = 0; i < recommendations.length; i+=2) {
+            String[] minuendParts = StringUtil
+                .unbracket(recommendations[i+0])
+                .split(";");
+            if(minuendParts.length >= 4) {
+                displayString += "(" + minuendParts[3];
+            }
+            else {
+                displayString += "([error]";
+            }
+
+            displayString += " - ";
+
+            String[] subtrahendParts = StringUtil
+                .unbracket(recommendations[i+1])
+                .split(";");
+            if(subtrahendParts.length >= 4) {
+                displayString += subtrahendParts[3] + ") ";
+            }
+            else {
+                displayString += "[error])";
+            }
+        }
+
+        return new String[] { displayString };
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,16 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DifferencesState extends DefaultState {
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(DifferencesState.class);
+
+    public DifferencesState() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java	Tue Aug 28 11:45:23 2012 +0000
@@ -0,0 +1,59 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class YearEpochSelect extends DefaultState {
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(YearEpochSelect.class);
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public YearEpochSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "minfo.bed.year_epoch";
+    }
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator ec,
+        Artifact                artifact,
+        String                  name,
+        CallContext             context)
+    {
+        CallMeta meta = context.getMeta();
+        Element[] elements = new Element[2];
+        elements[0] = createItem(
+                ec,
+                new String[] {
+                    Resources.getMsg(meta,
+                        "state.minfo.year",
+                        "state.minfo.year"),
+                    "year"});
+
+        elements[1] = createItem(
+            ec,
+            new String[] {
+                Resources.getMsg(meta,
+                    "state.minfo.epoch",
+                    "state.minfo.epoch"),
+                "epoch"});
+
+        return elements;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
\ No newline at end of file
--- a/flys-artifacts/src/main/resources/messages.properties	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages.properties	Tue Aug 28 11:45:23 2012 +0000
@@ -43,6 +43,13 @@
 state.minfo.sq.location=Location
 state.minfo.sq.period=Periods
 state.minfo.sq.outliers=Outliers
+state.minfo.bed.year_epoch=Year/Epoch
+state.minfo.bed.difference_select=Differences
+state.minfo.year=Year
+state.minfo.epoch=Epoch
+
+year=Year
+epoch=Epoch
 
 historical.mode.w = Waterlevel Analyse
 historical.mode.q = Discharge Analyse
--- a/flys-artifacts/src/main/resources/messages_de.properties	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_de.properties	Tue Aug 28 11:45:23 2012 +0000
@@ -43,6 +43,13 @@
 state.minfo.sq.location=Ort
 state.minfo.sq.period=Zeitraum
 state.minfo.sq.outliers=Ausrei\u00dfer
+state.minfo.bed.year_epoch=Jahr/Epoche
+state.minfo.bed.difference_select=Differenzen
+state.minfo.year=Jahr
+state.minfo.epoch=Epoche
+
+year=Jahr
+epoch=Epoche
 
 historical.mode.w = Wasserstandsanalyse
 historical.mode.q = Abflussanalyse
--- a/flys-artifacts/src/main/resources/messages_de_DE.properties	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_de_DE.properties	Tue Aug 28 11:45:23 2012 +0000
@@ -43,6 +43,13 @@
 state.minfo.sq.location=Ort
 state.minfo.sq.period=Zeitraum
 state.minfo.sq.outliers=Ausrei\u00dfer
+state.minfo.bed.year_epoch=Jahr/Epoche
+state.minfo.bed.difference_select=Differenzen
+state.minfo.year=Jahr
+state.minfo.epoch=Epoche
+
+year=Jahr
+epoch=Epoche
 
 historical.mode.w = Wasserstandsanalyse
 historical.mode.q = Abflussanalyse
--- a/flys-artifacts/src/main/resources/messages_en.properties	Mon Aug 27 10:52:12 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_en.properties	Tue Aug 28 11:45:23 2012 +0000
@@ -43,6 +43,13 @@
 state.minfo.sq.location=Location
 state.minfo.sq.period=Periods
 state.minfo.sq.outliers=Outliers
+state.minfo.bed.year_epoch=Year/Epoch
+state.minfo.bed.difference_select=Differences
+state.minfo.year=Year
+state.minfo.epoch=Epoch
+
+year=Year
+epoch=Epoch
 
 historical.mode.w = Waterlevel Analyse
 historical.mode.q = Discharge Analyse

http://dive4elements.wald.intevation.org